Decomposition of potato yield gap in the Andean north of Peru

A crop modeling approach

Background

This repository is designed to provide comprehensive documentation of the R code used for the analysis of yield gap decomposition, integrating both crop modeling and stochastic frontier analysis.

Libraries and extra R-files

The following libraries were used:

# libraries
library(nasapower)
library(meteor)
library(lubridate)
library(Metrics)
library(dplyr)
library(tidyr)
library(minpack.lm)
library(ggplot2)

Additionally, extra R-files need to be loaded.

# extra R-files
load(url("https://github.com/jninanya/solanumR/raw/refs/heads/main/CropParamsList.Rdata"))
source("https://raw.githubusercontent.com/jninanya/solanumR/refs/heads/main/thermalTime.R")
source("https://raw.githubusercontent.com/jninanya/solanumR/refs/heads/main/SolanumModel.R")

Field experiment and data collection

A field experiment was conducted to determine the potential yield of the five most commonly grown potato varieties in Chugay, La Libertad, Peru: Amarillis, Bretaña, Huevo de Indio, Poderosa, and Yungay. These varieties were managed under optimal growing conditions to assess their yield potential. The trial took place from 24th October 2023 to 18th April 2024, providing insights into how these varieties perform in a local context under “ideal” conditions.

Figura 1: Field experiment to determine potential yield of the most common potato varieties in Chugay Distric, La-Libertad region, Peru.
Figura 1: Field experiment to determine potential yield of the most common potato varieties in Chugay Distric, La-Libertad region, Peru.

A total of five biomass evaluations were carried out, where the plant organs (leaf, stem, root, and tubers) were separated, every two weeks from the tuberization stage to harvest. Additionally, fifteen canopy cover evaluations were conducted from plant emergence to senescence, providing detailed data on the growth and development of the five potato varieties. The dataset related to this field experiment can be downloaded at https://doi.org/10.21223/JPA3NZ.

Biomass data

Lets see the harvest index, i.e., the ratio of tuber biomass over total biomass. Click on code to see the R chunk code for the canopy biomass data.

#---------------------------------------------------------------
# SUMMARY OF BIOMASS DATA
#---------------------------------------------------------------
BD <- read.csv("https://github.com/jninanya/Potato_Yield_Gap/raw/refs/heads/main/Data/biomass_dataset.csv")
#head(BD)

# Constant to convert kg/plant to t/ha
k = (1/1000)*(1/(0.3*1))*(10000/1)*0.001

# Matter concentration of <organ> (MCX)
BD$MCL <- BD$sDLM/BD$sFLM      # L = leaf
BD$MCS <- BD$sDSM/BD$sFSM      # S = stem
BD$MCR <- BD$sDRM/BD$sFRM      # R = root
BD$MCT <- BD$sDTM/BD$sFTM      # T = tuber
BD$DMC <- BD$MCT                 

# Dry <organ> matter (DXM)
BD$DLM <- BD$FLM*BD$MCL
BD$DSM <- BD$FSM*BD$MCS
BD$DRM <- BD$FRM*BD$MCR
BD$DTM <- BD$FTM*BD$MCT

# Fresh <organ> yield (FXY)
BD$FLY <- BD$FLM*k
BD$FSY <- BD$FSM*k
BD$FRY <- BD$FRM*k
BD$FTY <- BD$FTM*k               

# Dry <organ> yield (DXY)
BD$DLY <- BD$DLM*k
BD$DSY <- BD$DSM*k
BD$DRY <- BD$DRM*k
BD$DTY <- BD$DTM*k

# Total dry matter (TDM) and harvest index (HI)
BD$TDM <- BD$DLY + BD$DSY + BD$DRY + BD$DTY
BD$HI <- BD$DTY/BD$TDM

# Summary: mean and standard error for HI
smrBD <- BD %>%
  group_by(CODE, EVAL, DAP) %>%
  summarise(DLY = mean(DLY, na.rm = TRUE),
            DSY = mean(DSY, na.rm = TRUE),
            DRY = mean(DRY, na.rm = TRUE),
            DTY = mean(DTY, na.rm = TRUE),
            FTY = mean(FTY, na.rm = TRUE),
            TDM = mean(TDM, na.rm = TRUE),
            DMC = mean(DMC, na.rm = TRUE),
            N = sum(!is.na(HI)),
            nd = n(),
            HI_mean = mean(HI, na.rm = TRUE),
            HI_se = sd(HI, na.rm = TRUE)/sqrt(N)
    )
smrBD <- as.data.frame(smrBD)

outBD <- smrBD[, c("CODE","DAP","HI_mean")] %>%
  pivot_wider(names_from = CODE, values_from = HI_mean)
outBD

outTDM <- smrBD[, c("CODE","DAP","TDM")] %>%
  pivot_wider(names_from = CODE, values_from = TDM)
outTDM <- as.data.frame(outTDM)

outDMC <- smrBD[, c("CODE","DAP","DMC")] %>%
  pivot_wider(names_from = CODE, values_from = DMC)
outDMC <- as.data.frame(outDMC)

outFTY <- smrBD[, c("CODE","DAP","FTY")] %>%
  pivot_wider(names_from = CODE, values_from = FTY)
outFTY <- as.data.frame(outFTY)

# Data frame for each variety
AMA <- smrBD[smrBD$CODE=="AMA",]
BRE <- smrBD[smrBD$CODE=="BRE",]
HUE <- smrBD[smrBD$CODE=="HUE",]
POD <- smrBD[smrBD$CODE=="POD",]
YUN <- smrBD[smrBD$CODE=="YUN",]

# General plot settings
par(oma    = c(4.5, 4.5, 0.5, 3),  # general margins
    mfrow  = c(1, 5),                # number of sub-figures
    mar    = c(0, 0, 0, 0),          # margins per sub-figure
    family = "serif",                # text family
    lwd    = 1.0,                    # line width
    las    = 1,                      # style of axis labels  
    pch    = 19,                     # plotting points
    cex    = 0.8
)

# Color and y-axis limits
pC <- c("blue","yellow","green","cyan","red") 
yL <- c(0,1) 

# Plot for Amarilis
with(AMA, plot(x=DAP, y=HI_mean, ylim=yL, col=pC[1], axes=FALSE, xlab="", ylab=""))
with(AMA, lines(x=DAP, y=HI_mean, lty=2, col=pC[1]))
box(); axis(2); axis(4, labels=FALSE);axis(1)
mtext(side=2, "Harvest Index", line=3, las=0)

# Plot for Bretana
with(BRE, plot(x=DAP, y=HI_mean, ylim=yL, col=pC[2], axes=FALSE, xlab="", ylab=""))
with(BRE, lines(x=DAP, y=HI_mean, lty=2, col=pC[2]))
box(); axis(2,labels=FALSE); axis(4, labels=FALSE);axis(1)

# Plot for Huevo de Indio
with(HUE, plot(x=DAP, y=HI_mean, ylim=yL, col=pC[3], axes=FALSE, xlab="", ylab=""))
with(HUE, lines(x=DAP, y=HI_mean, lty=2, col=pC[3]))
box(); axis(2,labels=FALSE); axis(4, labels=FALSE);axis(1)
mtext(side=1, "Days after planting", line=3)

# Plot for Poderosa
with(POD, plot(x=DAP, y=HI_mean, ylim=yL, col=pC[4], axes=FALSE, xlab="", ylab=""))
with(POD, lines(x=DAP, y=HI_mean, lty=2, col=pC[4]))
box(); axis(2,labels=FALSE); axis(4, labels=FALSE);axis(1)

# Plot for Yungay
with(YUN, plot(x=DAP, y=HI_mean, ylim=yL, col=pC[5], axes=FALSE, xlab="", ylab=""))
with(YUN, lines(x=DAP, y=HI_mean, lty=2, col=pC[5]))
box(); axis(2,labels=FALSE); axis(4);axis(1)

## # A tibble: 6 × 6
##     DAP    AMA    BRE    HUE    POD    YUN
##   <int>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
## 1    94  0.596  0.208  0.277  0.148  0.245
## 2   101  0.668 NA     NA     NA     NA    
## 3   113  0.727  0.376  0.477  0.405  0.434
## 4   136  0.834  0.599  0.706  0.677  0.674
## 5   154  0.872  0.700  0.803  0.718  0.766
## 6   178 NA      0.729  0.854  0.790  0.856

Canopy cover data

Click on code to see the R chunk code for the canopy cover data.

#---------------------------------------------------------------
# SUMMARY OF CANOPY COVER DATA
#---------------------------------------------------------------
CD <- read.csv("https://github.com/jninanya/Potato_Yield_Gap/raw/refs/heads/main/Data/canopy_cover_dataset.csv")
#head(CD)

# Summary by variety and evaluation
smrCD <- CD %>%
  group_by(CODE, DAP) %>%
  summarise(N = sum(!is.na(CC)),
            nd = n(),
            CC_mean = mean(CC, na.rm = TRUE),
            CC_se = sd(CC, na.rm = TRUE)/sqrt(N),
  )

smrCD <- as.data.frame(smrCD)

# Data frame per variety
outCD <- smrCD[, c("CODE","DAP","CC_mean")] %>%
  pivot_wider(names_from = CODE, values_from = CC_mean)
outCD

# Data frame for each variety
AMA <- smrCD[smrCD$CODE=="AMA",]
BRE <- smrCD[smrCD$CODE=="BRE",]
HUE <- smrCD[smrCD$CODE=="HUE",]
POD <- smrCD[smrCD$CODE=="POD",]
YUN <- smrCD[smrCD$CODE=="YUN",]

# General plot settings
par(oma    = c(4.5, 4.5, 0.5, 3),  # general margins
    mfrow  = c(1, 5),                # number of sub-figures
    mar    = c(0, 0, 0, 0),          # margins per sub-figure
    family = "serif",                # text family
    lwd    = 1.0,                    # line width
    las    = 1,                      # style of axis labels  
    pch    = 19,                     # plotting points
    cex    = 0.8
)

# Color and y-axis limits
pC <- c("blue","yellow","green","cyan","red") 
yL <- c(0,100) 

# Plot for Amarilis
with(AMA, plot(x=DAP, y=CC_mean, ylim=yL, col=pC[1], axes=FALSE, xlab="", ylab=""))
with(AMA, lines(x=DAP, y=CC_mean, lty=2, col=pC[1]))
box(); axis(2); axis(4, labels=FALSE);axis(1)
mtext(side=2, "Canopy cover (%)", line=3, las=0)

# Plot for Bretana
with(BRE, plot(x=DAP, y=CC_mean, ylim=yL, col=pC[2], axes=FALSE, xlab="", ylab=""))
with(BRE, lines(x=DAP, y=CC_mean, lty=2, col=pC[2]))
box(); axis(2,labels=FALSE); axis(4, labels=FALSE);axis(1)

# Plot for Huevo de Indio
with(HUE, plot(x=DAP, y=CC_mean, ylim=yL, col=pC[3], axes=FALSE, xlab="", ylab=""))
with(HUE, lines(x=DAP, y=CC_mean, lty=2, col=pC[3]))
box(); axis(2,labels=FALSE); axis(4, labels=FALSE);axis(1)
mtext(side=1, "Days after planting", line=3)

# Plot for Poderosa
with(POD, plot(x=DAP, y=CC_mean, ylim=yL, col=pC[4], axes=FALSE, xlab="", ylab=""))
with(POD, lines(x=DAP, y=CC_mean, lty=2, col=pC[4]))
box(); axis(2,labels=FALSE); axis(4, labels=FALSE);axis(1)

# Plot for Yungay
with(YUN, plot(x=DAP, y=CC_mean, ylim=yL, col=pC[5], axes=FALSE, xlab="", ylab=""))
with(YUN, lines(x=DAP, y=CC_mean, lty=2, col=pC[5]))
box(); axis(2,labels=FALSE); axis(4);axis(1)

## # A tibble: 15 × 6
##      DAP    AMA   BRE   HUE   POD   YUN
##    <int>  <dbl> <dbl> <dbl> <dbl> <dbl>
##  1    52   9.72  1.61  2.61  7.66   0  
##  2    59  35.8  25.7  18.3  27.0   22.4
##  3    65  45.0  36.6  26.2  41.9   32.8
##  4    67  51.5  42.8  31.4  53.3   38.1
##  5    70  65.4  47.7  39.3  70.3   46.3
##  6    76  78.1  60.1  50.0  86.1   57.7
##  7    80  84.7  67.2  52.9  91.4   66.7
##  8    86  83.7  68.7  50.6  92.9   63.2
##  9    98  88.7  83.9  65.7  95.3   76.8
## 10   110  94.4  93.6  77.6  96.2   82.1
## 11   121  86.7  89.2  79.8  96.0   85.3
## 12   129  78.5  87.6  72.6  88.5   85.1
## 13   149  41.8  85.5  64.4  45.8   65.7
## 14   156 NaN    70.9  44.1  19.5   36.4
## 15   165 NaN    58.5  24.8  11.4   21.8

Biass correction of weather data

A bias correction of NASAPower weather data was performed using information from an in situ weather station. The correction methods applied included linear regression, quantile matching, and statistical distribution with spline cubics. Although the in situ weather station provided data for only one year, a 10-year weather dataset was generated using the bias-corrected NASAPower data (to avoid seasonality error), ensuring it accurately reflects local conditions during the experiment.

A simple bias correction was chosen, and the minimum temperature, maximum temperature, and solar radiation were corrected. If you would like to see the code chunk, click on code.

#---------------------------------------------------------------
# RETRIEVE DATA FROM NASA POWER
#---------------------------------------------------------------
# Define variables (wvars) and period
wvars <- c("T2M_MAX", "T2M_MIN", "ALLSKY_SFC_SW_DWN")
period <- c("2000-01-01", "2024-05-31")

# Coordinates (lon, lat)
PRO <- c(-77.82, -7.75) 

# Get daily data from NASA POWER 
wdata <- get_power(
  community = "ag",
  lonlat = PRO,
  pars = wvars,
  dates = period,
  temporal_api = "daily"
)

wd <- data.frame(date = wdata$YYYYMMDD, tmin = wdata$T2M_MIN,
                 tmax = wdata$T2M_MAX, srad = wdata$ALLSKY_SFC_SW_DWN)

#---------------------------------------------------------------
# CORRECT DATA FROM NASA POWER
#---------------------------------------------------------------
# Local weather data
df <- read.csv("https://github.com/jninanya/Potato_Yield_Gap/raw/refs/heads/main/Data/dataset_for_model_calibration.csv")
colnames(df) <- tolower(colnames(df))

# Growing season
swgDate <- as.Date("2023-10-24")
hvtDate <- as.Date("2024-04-18")
GS <- seq(swgDate, hvtDate, by = 1)

wdS <- wd[wd$date >= swgDate & wd$date <= hvtDate, ]
wdO <- df
#sum(wdS$date == wdO$date) == length(wdO$date)

# Create samples for training and validation
set.seed(333)
nT <- 1:nrow(wdO)               # n total
nS <- round(0.70*nrow(wdO), 0)  # n sample
Tperiod <- sample(nT, nS)
Vperiod <- nT[-Tperiod]

# Performance metrics
nM <- 5
M1 <- matrix(nrow = nM, ncol = 3) # RRMSE
M2 <- matrix(nrow = nM, ncol = 3) # RMSE
M3 <- matrix(nrow = nM, ncol = 3) # R2
M4 <- matrix(nrow = nM, ncol = 3) # m (slope)

outBC <- list()  # Bias Correction
outLR <- list()  # Linear Regression
outQM <- list()  # Quantile Matching
outSD <- list()  # Statistical Distribution

for(i in 1:3){
  
  obsT = wdO[Tperiod, 1+i]
  simT = wdS[Tperiod, 1+i]
  
  obsV = wdO[Vperiod, 1+i]
  simV = wdS[Vperiod, 1+i]
  
  # Without any correction
  actual = obsV
  predicted = simV
  REG = summary(lm(actual ~ predicted + 0))
  M1[1, i] = round(rmse(actual, predicted)/mean(actual)*100, 1)
  M2[1, i] = round(rmse(actual, predicted), 2)
  M3[1, i] = round(REG$adj.r.squared, 2)
  M4[1, i] = round(REG$coefficients[1,1], 2)
  
  # Bias correction
  bias = mean(obsT - simT)
  obsC = simV + bias
  actual = obsV
  predicted = obsC
  REG = summary(lm(actual ~ predicted + 0))
  M1[2, i] = round(rmse(actual, predicted)/mean(actual)*100, 1)
  M2[2, i] = round(rmse(actual, predicted), 2)
  M3[2, i] = round(REG$adj.r.squared, 2)
  M4[2, i] = round(REG$coefficients[1,1], 2)
  
  # Linear regression
  LR = lm(obsT ~ simT)
  obsC = predict(LR, newdata = data.frame(simT = simV))
  actual = obsV
  predicted = obsC
  REG = summary(lm(actual ~ predicted + 0))
  M1[3, i] = round(rmse(actual, predicted)/mean(actual)*100, 1)
  M2[3, i] = round(rmse(actual, predicted), 2)
  M3[3, i] = round(REG$adj.r.squared, 2)
  M4[3, i] = round(REG$coefficients[1,1], 2)
  
  # Quantile matching
  common_quantiles = seq(0, 1, length.out = 100)
  sCDF = quantile(simT, probs = common_quantiles)
  oCDF = quantile(obsT, probs = common_quantiles)
  QM = lm(oCDF ~ sCDF)
  obsC = simV*coef(QM)[2] + coef(QM)[1]
  actual = obsV
  predicted = obsC
  REG = summary(lm(actual ~ predicted + 0))
  M1[4, i] = round(rmse(actual, predicted)/mean(actual)*100, 1)
  M2[4, i] = round(rmse(actual, predicted), 2)
  M3[4, i] = round(REG$adj.r.squared, 2)
  M4[4, i] = round(REG$coefficients[1,1], 2)
  
  # Statistical distribution with sline cubics 
  sort_obs = sort(obsT)
  sort_sim = sort(simT)
  SD = smooth.spline(sort_sim, sort_obs)
  obsC = predict(SD, simV)$y
  actual = obsV
  predicted = obsC
  REG = summary(lm(actual ~ predicted + 0))
  M1[5, i] = round(rmse(actual, predicted)/mean(actual)*100, 1)
  M2[5, i] = round(rmse(actual, predicted), 2)
  M3[5, i] = round(REG$adj.r.squared, 2)
  M4[5, i] = round(REG$coefficients[1,1], 2)
  
  outBC[[i]] = bias 
  outLR[[i]] = LR 
  outQM[[i]] = QM
  outSD[[i]] = SD
  
}

colnames(M1) <- colnames(M2) <- c("tmin", "tmax", "srad")
colnames(M4) <- colnames(M3) <- c("tmin", "tmax", "srad")

rownames(M1) <- rownames(M2) <- c("NC", "BC", "LR", "QM", "SD")
rownames(M3) <- rownames(M4) <- c("NC", "BC", "LR", "QM", "SD")

names(outBC) <- names(outLR) <- c("tmin", "tmax", "srad")
names(outQM) <- names(outSD) <- c("tmin", "tmax", "srad")


#---------------------------------------------------------------
# PLOTS
#---------------------------------------------------------------
# General plot settings
par(oma    = c(4.5, 4.5, 0.5, 3),  # general margins
    mfrow  = c(4, 3),                # number of sub-figures
    mar    = c(4.5,2.5,1.5,1.5),          # margins per sub-figure
    family = "serif",                # text family
    lwd    = 1.0,                    # line width
    las    = 1,                      # style of axis labels  
    pch    = 19,                     # plotting points
    cex    = 0.5,
    pty = "s"
)

# PLOTS FOR SIMPLE BIAS CORRECTION
tminC = wdS$tmin + outBC$tmin
plot(wdS$tmin, wdO$tmin, xlim = c(0,14), ylim = c(0,14), xlab = "NASA: tmin (C)", ylab = "OBS: tmin (C)", col = "blue")
points(tminC, wdO$tmin, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)

tmaxC = wdS$tmax + outBC$tmax
plot(wdS$tmax, wdO$tmax, xlim = c(8,28), ylim = c(8,28), xlab = "NASA: tmax (C)", ylab = "OBS: tmax (C)", col = "blue")
points(tmaxC, wdO$tmax, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)
title("Biass Correction")

sradC = wdS$srad + outBC$srad
plot(wdS$srad, wdO$srad, xlim = c(3,31), ylim = c(3,31), xlab = "NASA: srad (MJ/m2/day)", ylab = "OBS: srad (MJ/m2/day)", col = "blue")
points(sradC, wdO$srad, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)


# PLOTS FOR LINEAR REGRESSION
tminC = predict(outLR$tmin, newdata = data.frame(simT = wdS$tmin))
plot(wdS$tmin, wdO$tmin, xlim = c(0,14), ylim = c(0,14), xlab = "NASA: tmin (C)", ylab = "OBS: tmin (C)", col = "blue")
points(tminC, wdO$tmin, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)

tmaxC = predict(outLR$tmax, newdata = data.frame(simT = wdS$tmax))
plot(wdS$tmax, wdO$tmax, xlim = c(8,28), ylim = c(8,28), xlab = "NASA: tmax (C)", ylab = "OBS: tmax (C)", col = "blue")
points(tmaxC, wdO$tmax, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)
title("Linear Regression")

sradC = predict(outLR$srad, newdata = data.frame(simT = wdS$srad))
plot(wdS$srad, wdO$srad, xlim = c(3,31), ylim = c(3,31), xlab = "NASA: srad (MJ/m2/day)", ylab = "OBS: srad (MJ/m2/day)", col = "blue")
points(sradC, wdO$srad, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)


# PLOTS FOR QUANTILE MATCHING
tminC = predict(outQM$tmin, newdata = data.frame(sCDF = wdS$tmin))
plot(wdS$tmin, wdO$tmin, xlim = c(0,14), ylim = c(0,14), xlab = "NASA: tmin (C)", ylab = "OBS: tmin (C)", col = "blue")
points(tminC, wdO$tmin, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)

tmaxC = predict(outQM$tmax, newdata = data.frame(sCDF = wdS$tmax))
plot(wdS$tmax, wdO$tmax, xlim = c(8,28), ylim = c(8,28), xlab = "NASA: tmax (C)", ylab = "OBS: tmax (C)", col = "blue")
points(tmaxC, wdO$tmax, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)
title("Quantile Matching")

sradC = predict(outQM$srad, newdata = data.frame(sCDF = wdS$srad))
plot(wdS$srad, wdO$srad, xlim = c(3,31), ylim = c(3,31), xlab = "NASA: srad (MJ/m2/day)", ylab = "OBS: srad (MJ/m2/day)", col = "blue")
points(sradC, wdO$srad, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)


# PLOT FOR STATISTICAL DISTRIBUTION USING SPLINES
tminC = predict(outSD$tmin, wdS$tmin)$y
plot(wdS$tmin, wdO$tmin, xlim = c(0,14), ylim = c(0,14), xlab = "NASA: tmin (C)", ylab = "OBS: tmin (C)", col = "blue")
points(tminC, wdO$tmin, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)

tmaxC = predict(outSD$tmax, wdS$tmax)$y
plot(wdS$tmax, wdO$tmax, xlim = c(8,28), ylim = c(8,28), xlab = "NASA: tmax (C)", ylab = "OBS: tmax (C)", col = "blue")
points(tmaxC, wdO$tmax, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)
title("Statistical Distribution")

sradC = predict(outSD$srad, wdS$srad)$y
plot(wdS$srad, wdO$srad, xlim = c(3,31), ylim = c(3,31), xlab = "NASA: srad (MJ/m2/day)", ylab = "OBS: srad (MJ/m2/day)", col = "blue")
points(sradC, wdO$srad, col = "red")
abline(c(0,1), col = "black", lwd = 1.5)

#---------------------------------------------------------------
# FINAL WEATHER DATA FOR MODELING
#---------------------------------------------------------------
wo <- wd
wc <- data.frame(date = wd$date)

# Apply the quantile matching to dataset
wc$tmin <- predict(outQM$tmin, newdata = data.frame(sCDF = wo$tmin))
wc$tmax <- predict(outQM$tmax, newdata = data.frame(sCDF = wo$tmax))
wc$srad <- predict(outQM$srad, newdata = data.frame(sCDF = wo$srad))

# Final weather data
WD <- wc

SOLANUM model calibration

The SOLANUM model was calibrated using temporal data on canopy cover and biomass. Canopy cover data was fitted to a beta function, while biomass data was fitted to a Gompertz function. Nonlinear regression was applied for this calibration.

Click on code to view how the canopy cover data was fitted to the Beta curve using the FitCurveSM function in R.

# load thermal time function
source("../R/thermalTime.R")
source("../R/SolanumModel.R")
source("../R/FitCurveSM.R")

# Emergency day
ee <- data.frame(EDay=c(16, 33, 34, 24, 42),
                 CODE=c("AMA", "BRE", "HUE", "POD", "YUN"))
EDay <- ee$EDay
names(EDay) <- c("AMA", "BRE", "HUE", "POD", "YUN")

# Read weather data
wd <- read.csv("https://github.com/jninanya/Potato_Yield_Gap/raw/refs/heads/main/Data/dataset_for_model_calibration.csv")
colnames(wd) <- tolower(colnames(wd))

# Thermal time computation
TT <- matrix(nrow = length(wd$date), ncol = 5)

for(i in 1:5){
  tt = thermalTime(date = wd$date, tmin = wd$tmin, tmax = wd$tmax,
                   sowing = "2023-10-24", endHarvest = "2024-04-18",
                   EmergencyDays = EDay[i])
  TT[,i] = round(tt$tt,1)
}

colnames(TT) <- names(EDay)
rownames(TT) <- 0:(length(wd$date)-1)
#head(TT)

TT <- data.frame(date = wd$date, dap = 0:(length(wd$date)-1), TT)

# TT  per variety
outCD <- as.data.frame(outCD)
TT_CD <- TT[TT$dap %in% outCD$DAP, 2:7]

### function to calibrate the model
tm <- vector()
te <- vector()
wmax <- vector()
cc <- list()

for(i in 1:5){
  x <- TT_CD[, 1+i]
  y <- outCD[, 1+i]
  fitt.cc <- FitCurveSM(x, y, xfun = "Beta", xtime = "tt", 
                        init.par = c(100, 500, 0.9) , use.par.default = FALSE)
  
  tm[i] <- fitt.cc$parameters[1]
  te[i] <- fitt.cc$parameters[2]
  wmax[i] <- fitt.cc$parameters[3]
  
  cc[[i]] <- fitt.cc
}

# Crop parameters for the Beta function
names(tm) <- names(te) <- names(wmax) <- c("AMA", "BRE", "HUE", "POD", "YUN")
names(cc) <- c("AMA", "BRE", "HUE", "POD", "YUN")

############3
#############
############

par(mfrow = c(2,3),
    mar = c(2.5,3.5,2.5,0.5),
    las = 1, pty = "s", cex = 1.)
# PLOTS CC AMARILIS
plot(cc$AMA$simulated.data$time, cc$AMA$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "canopy cover (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Amarilis", xlim = c(0,1400))
points(cc$AMA$fitted.data$time, cc$AMA$fitted.data$obs/100, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS CC BRETANA
plot(cc$BRE$simulated.data$time, cc$BRE$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "canopy cover (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Bretaña", xlim = c(0,1400))
points(cc$BRE$fitted.data$time, cc$BRE$fitted.data$obs/100, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS CC HUEVO DE INDIO
plot(cc$HUE$simulated.data$time, cc$HUE$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "canopy cover (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Huevo de Indio", xlim = c(0,1400))
points(cc$HUE$fitted.data$time, cc$HUE$fitted.data$obs/100, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS CC PODEROSA
plot(cc$POD$simulated.data$time, cc$POD$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "canopy cover (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Poderosa", xlim = c(0,1400))
points(cc$POD$fitted.data$time, cc$POD$fitted.data$obs/100, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS CC YUNGAY
plot(cc$YUN$simulated.data$time, cc$YUN$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "canopy cover (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Yungay", xlim = c(0,1400))
points(cc$YUN$fitted.data$time, cc$YUN$fitted.data$obs/100, col = "red", lwd = 1.2, cex = 1.5)

Click on code to view how the harvest index (tuber/total biomass) data was fitted to the Gompertz curve using the FitCurveSM function in R.

#---------------------
# BIOMASS 
#------------------------------------------

#### dates 
outBD <- as.data.frame(outBD)
outBD$DAP[6] <- 177
zeros_row <- rep(0, 6)
last_row <- c(185, apply(outBD[,2:6], 2, max, na.rm=TRUE))
outBD_new <- rbind(zeros_row, outBD)
outBD_new <- rbind(outBD_new, last_row)
#outBD_new$AMA[7] <- outBD_new$AMA[8]
#outBD_new$AMA[8] <- NA

TT_BD <- TT[TT$dap %in% outBD$DAP, 2:7]
zeros_row <- rep(0, 6)
last_row <- c(185, unlist(TT_BD[6,2:6]) + 150)
TT_BD_new <- rbind(zeros_row, TT_BD)
TT_BD_new <- rbind(TT_BD_new, last_row)

############################
###########################
b <- vector()
tu <- vector()
A <- vector()
hh <- list()

for(i in 1:5){
  x <- TT_BD[, 1+i]
  y <- outBD[, 1+i]
  
  fitt.hh <- FitCurveSM(x, y, xfun = "Gompertz", xtime = "tt", 
                        init.par = c(250, 600, 0.9) , use.par.default = FALSE)
  
  b[i] <- fitt.hh$parameters[1]
  tu[i] <- fitt.hh$parameters[2]
  A[i] <- fitt.hh$parameters[3]
  
  hh[[i]] <- fitt.hh
}

names(b) <- names(tu) <- names(A) <- c("AMA", "BRE", "HUE", "POD", "YUN")
names(hh) <- c("AMA", "BRE", "HUE", "POD", "YUN")


############3
#############
############

par(mfrow = c(2,3),
    mar = c(2.5,3.5,2.5,0.5),
    las = 1, pty = "s", cex = 1.)
# PLOTS HI AMARILIS
plot(hh$AMA$simulated.data$time, hh$AMA$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "harvest index (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Amarilis", xlim = c(0,1700))
points(hh$AMA$fitted.data$time, hh$AMA$fitted.data$obs, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS HI BRETANA
plot(hh$BRE$simulated.data$time, hh$BRE$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "harvest index (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Bretaña", xlim = c(0,1700))
points(hh$BRE$fitted.data$time, hh$BRE$fitted.data$obs, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS CC HUEVO DE INDIO
plot(hh$HUE$simulated.data$time, hh$HUE$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "harvest index (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Huevo de Indio", xlim = c(0,1700))
points(hh$HUE$fitted.data$time, hh$HUE$fitted.data$obs, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS CC PODEROSA
plot(hh$POD$simulated.data$time, hh$POD$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "harvest index (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Poderosa", xlim = c(0,1700))
points(hh$POD$fitted.data$time, hh$POD$fitted.data$obs, col = "red", lwd = 1.2, cex = 1.5)

# PLOTS CC YUNGAY
plot(hh$YUN$simulated.data$time, hh$YUN$simulated.data$simulated_data,
     xlab = "thermal time (C*day)", ylab = "harvest index (%)", las = 1, ylim = c(0,1),
     type = "l", lwd = 1.5, main = "Yungay", xlim = c(0,1700))
points(hh$YUN$fitted.data$time, hh$YUN$fitted.data$obs, col = "red", lwd = 1.2, cex = 1.5)


##################

tm.dap <- vector()
te.dap <- vector()
wmax.dap <- vector()

for(i in 1:5){
  x <- TT_CD$dap
  y <- outCD[, 1+i]
  fitt.cc <- FitCurveSM(x, y, xfun = "Beta", xtime = "dap", 
                        init.par = c(40, 120, 0.9) , use.par.default = FALSE)
  
  tm.dap[i] <- fitt.cc$parameters[1]
  te.dap[i] <- fitt.cc$parameters[2]
  wmax.dap[i] <- fitt.cc$parameters[3]
  
}

names(tm.dap) <- names(te.dap) <- names(wmax.dap) <- c("AMA", "BRE", "HUE", "POD", "YUN")


###############################################
# beta function
f_beta <- function(t, tm, te, wmax){
  cc=wmax*(1+(te-t)/(te-tm))*((t/te)^(te/(te-tm)))
  cc=ifelse(cc>0, cc, 0)
}

# gompertz function
f_gompertz <- function(t, b, tu, A){
  A*(exp(-exp(-(1/b)*(t-tu))))
}


### CC daily basis
var <- c("AMA", "BRE", "HUE", "POD", "YUN")

wd$dap <- 0:(length(wd$date)-1)
wd$ccAMA <- f_beta(wd$dap, tm.dap["AMA"], te.dap["AMA"], wmax.dap["AMA"])
wd$ccBRE <- f_beta(wd$dap, tm.dap["BRE"], te.dap["BRE"], wmax.dap["BRE"])
wd$ccHUE <- f_beta(wd$dap, tm.dap["HUE"], te.dap["HUE"], wmax.dap["HUE"])
wd$ccPOD <- f_beta(wd$dap, tm.dap["POD"], te.dap["POD"], wmax.dap["POD"])
wd$ccYUN <- f_beta(wd$dap, tm.dap["YUN"], te.dap["YUN"], wmax.dap["YUN"])

wd$par <- wd$srad*0.48
wd$intAMA <- wd$srad*wd$ccAMA
wd$intBRE <- wd$srad*wd$ccBRE
wd$intHUE <- wd$srad*wd$ccHUE
wd$intPOD <- wd$srad*wd$ccPOD
wd$intYUN <- wd$srad*wd$ccYUN

wd$cumAMA <- cumsum(wd$intAMA)
wd$cumBRE <- cumsum(wd$intBRE)
wd$cumHUE <- cumsum(wd$intHUE)
wd$cumPOD <- cumsum(wd$intPOD)
wd$cumYUN <- cumsum(wd$intYUN)

CUM <- data.frame(AMA = wd$cumAMA[TT_BD$dap],
                  BRE = wd$cumBRE[TT_BD$dap],
                  HUE = wd$cumHUE[TT_BD$dap],
                  POD = wd$cumPOD[TT_BD$dap],
                  YUN = wd$cumYUN[TT_BD$dap])


RUE <- c(summary(lm(outTDM$AMA*100 ~ CUM$AMA))$coefficients[2],
         summary(lm(outTDM$BRE*100 ~ CUM$BRE))$coefficients[2],
         summary(lm(outTDM$HUE*100 ~ CUM$HUE))$coefficients[2],
         summary(lm(outTDM$POD*100 ~ CUM$POD))$coefficients[2],
         summary(lm(outTDM$YUN*100 ~ CUM$YUN))$coefficients[2])
names(RUE) <- var

DMC.bck <- outDMC 
DMC = apply(DMC.bck[,2:6],2,max,na.rm=TRUE)

VAR = names(DMC)
params <- data.frame(VAR, 
                     round(te,1), round(tm,1), round(wmax,2), 
                     round(b,1), round(tu,1), round(A,2),
                     round(RUE,2), round(DMC,2))

colnames(params)<- c("CODE","te","tm","wmax",
                     "b","tu","A","RUE","DMC")
rownames(params) <- 1:5

The crop parameters of the SOLANUM model were determined for each variety.

Table 1. Crop parameters of the SOLANUM model for the 5 most common varieties used in Chugay, La Libertad, in Peru.
PARAMETER AMARILIS BRETANA HUEVO DE INDIO PODEROSA YUNGAY
thermal time at the maximum growth rate (te) 973.2 946.8 904.9 895.1 784.0
thermal time at the maximum canopy cover (tm) 481.2 314.7 371.6 350.1 222.4
maximum canopy cover (wmax) 0.96 0.95 0.79 1.00 0.88
thermal time at the initial slope of partition curve (b) 273.2 256.7 269.7 204.0 294.6
thermal time at the maximum growth rate of partition curve (tu) 547.6 700.8 662.6 816.4 628.1
maximum harvest index (A) 0.90 0.76 0.89 0.80 0.90
radiation use efficiency (RUE) 1.20 1.11 1.28 1.69 1.82
dry matter concentration of tubers (DMC) 0.17 0.24 0.24 0.23 0.18

Determination of optimum planting date

Determination of optimum planting date involves identifying the best time to plant a crop to maximize yield and minimize risks from adverse weather conditions, pests, or diseases. This process considers factors such as temperature, rainfall, and day length to ensure optimal growth conditions. For this, data from the Integrated Agricultural Statistics System was used to support the analysis and identify the most suitable planting dates based on historical agricultural and climatic trends.

s1 <- read.csv("../Data/out_national_potato_data.csv")

# data for La Libertad
LL <- s1[s1$DEPARTAMENTO == "LA LIBERTAD", ]
#summary(LL)
LL$YYYY <- LL$ANIO
LL$MM <- LL$MES

# check COSECHA==0 & PRODUCCION==0
#sum(LL$PRODUCCION[LL$COSECHA == 0])
#sum(LL$COSECHA[LL$PRODUCTO == 0])

# montly summary for LL
smrLL.M <- LL %>%
  group_by(YYYY,MM) %>%
  summarise(SIEMBRA = sum(SIEMBRA),
            COSECHA = sum(COSECHA),
            PRODUCCION = sum(PRODUCCION))

# yearly summary for LL
smrLL.Y <- LL %>%
  group_by(YYYY) %>%
  summarise(SIEMBRA = sum(SIEMBRA),
            COSECHA = sum(COSECHA),
            PRODUCCION = sum(PRODUCCION))

# yield estimation
smrLL.Y <- as.data.frame(smrLL.Y)
smrLL.Y$RENDIMIENTO <- smrLL.Y$PRODUCCION/smrLL.Y$COSECHA

# data for Chugay
CH <- LL[LL$PROVINCIA == "SANCHEZ CARRION" & LL$DISTRITO == "CHUGAY", ]
#summary(CH)

# montly summary for LL
smrCH.M <- CH %>%
  group_by(YYYY,MM) %>%
  summarise(SIEMBRA = sum(SIEMBRA),
            COSECHA = sum(COSECHA),
            PRODUCCION = sum(PRODUCCION))

# data for figure
n <- length(smrCH.M$YYYY)
Year <- c(smrCH.M$YYYY, smrCH.M$YYYY)
Month <- c(smrCH.M$MM, smrCH.M$MM)
Area <- c(smrCH.M$SIEMBRA, smrCH.M$COSECHA)
Type <- c(rep("Planted", n), rep("Harvested", n))

df <- data.frame(Year, Month, Area, Type)
df$Year <- as.factor(Year)

# mean values
mean_values <- df %>%
  group_by(Month, Type) %>%
  summarize(mean_area = mean(Area, na.rm = TRUE))

# define double gaussian function
double_gaussian <- function(x, a1, b1, c1, a2, b2, c2) {
  a1 * exp(-(x - b1)^2 / (2 * c1^2)) + a2 * exp(-(x - b2)^2 / (2 * c2^2))
}

# fit curve
fit_models <- mean_values %>%
  group_by(Type) %>%
  do(fit = nlsLM(mean_area ~ double_gaussian(Month, a1, b1, c1, a2, b2, c2),
                 data = ., 
                 start = list(a1 = 10, b1 = 6, c1 = 1, a2 = 10, b2 = 10, c2 = 1)))

# save coefficients of the models
fit_params <- fit_models %>%
  rowwise() %>%
  mutate(params = list(coef(fit)))

# gaussian curves
gaussian_curves <- fit_params %>%
  rowwise() %>%
  do(data.frame(Month = seq(min(mean_values$Month), max(mean_values$Month), length.out = 100),
                Area = double_gaussian(seq(min(mean_values$Month), max(mean_values$Month), length.out = 100),
                                       .$params[[1]], .$params[[2]], .$params[[3]], 
                                       .$params[[4]], .$params[[5]], .$params[[6]]),
                Type = .$Type))


# pch
shape_values <- c(0, 1, 2, 3, 4, 5, 6, 7, 8)

# figure
gp <- ggplot(data = df) +
  geom_point(aes(x = Month, y = Area, shape = Year), 
             size = 2.5, col = "gray30") +
  scale_shape_manual(values = shape_values) +
  facet_wrap(~ Type) +
  labs(title = "Determining the optimum planting date for the cropping season in Chugay",
       y = "Area (ha)") + 
  geom_point(data = mean_values, aes(x = Month, y = mean_area), 
             col = "red", size = 3)+
  geom_line(data = gaussian_curves, aes(x = Month, y = Area), color = "blue", size = 1)

gp2 = gp
plot(gp2)

#####
#####

#x <- smrCH.M$MM
#y <- smrCH.M$SIEMBRA
#xm <- 1:12
#ym <- mean_values$mean_area[mean_values$Type == "Planted"]
#
#pointsColors <- rgb(0, 0, 0.99, alpha = 0.3)
#plot(x, y, axes = FALSE, xlab = "", ylab = "", 
#     pch = 20, col = pointsColors, cex = 1.2)
#box()
#
#points(xm, ym, pch = -30, col = "red", cex = 1.2, lwd = 1.5)

Determination of potential yields

Following the metodology of Silva et al. (2022), three types of potential yield (Ypa, Ypb, and Ypc) were used to evaluate and compare crop yield potential under different planting scenarios, considering variations in sowing dates and crop varieties.

  • Ypa represents the potential yield simulated for the highest-yielding variety, planted on the optimum sowing date for the growing season. This value reflects the maximum achievable yield for a specific site in a given season, using the best variety and the optimal planting date. The optimum sowing date is identified within a three-month window around the mean observed planting date in farmer field data, specifically within ± 6 weeks from this average date.

  • Ypb also represents simulated yield potential for the highest-yielding variety but is calculated using the actual planting dates observed in each specific field. Ypb provides an estimate of the potential yield attainable in each field with the highest-yielding variety on the recorded planting date.

  • Ypc simulates the yield potential based on both the actual variety used by the farmer and the actual planting date observed in each field. This measure reflects yield potential under the specific conditions chosen by the farmer, including both their selected variety and planting date. Importantly, Ypc does not account for the interaction between variety and sowing date, which can impact resource use efficiency.

In summary, Ypa represents the ideal maximum yield, Ypb indicates potential yield under real sowing dates but with the best variety, and Ypc shows the yield potential using the actual variety and sowing date selected by each farmer.

#-------------------------------------------------------------------------------
# Modeling potential yield
#-------------------------------------------------------------------------------

load("C:/Users/jninanya/OneDrive - CGIAR/noni/Github projects/Potato_Yield_Gap/R/CropParamsList.Rdata")
# consider 10 years
nyears <- 2010:2022

# Emergency day
ee <- data.frame(EDay=c(16, 33, 34, 24, 42),
                 CODE=c("AMA", "BRE", "HUE", "POD", "YUN"))
EDay <- ee$EDay
names(EDay) <- c("AMA", "BRE", "HUE", "POD", "YUN")


swgDates <- c("2020-03-05", "2020-03-10", "2020-03-15", "2020-03-20", "2020-03-25", "2020-03-30",
              "2020-04-05", "2020-04-10", "2020-04-15", "2020-04-20", "2020-04-25", "2020-04-30",
              "2020-08-05", "2020-08-10", "2020-08-15", "2020-08-20", "2020-08-25", "2020-08-30",
              "2020-09-05", "2020-09-10", "2020-09-15", "2020-09-20", "2020-09-25", "2020-09-30",
              "2020-10-05", "2020-10-10", "2020-10-15", "2020-10-20", "2020-10-25", "2020-10-30"
              )

hvtDAP <- 180

CP <- CropParamsList[c("AMA", "BRE", "HUE", "POD", "YUN")]
CParams <- list(CP[[1]], CP[[2]], CP[[3]], CP[[4]], CP[[5]])  
emgDays <- EDay

wdata <- as.data.frame(WD)
wdata$sunsh <- photoperiod(wdata$date, -7.75)
wdata$tmax = wdata$tmax + 1.0
wdata$tmin = wdata$tmin + 1.0

o0 <- as.data.frame(matrix(nrow = length(nyears), ncol = length(swgDates)))
o1 <- as.data.frame(matrix(nrow = length(nyears), ncol = length(swgDates)))
o2 <- as.data.frame(matrix(nrow = length(nyears), ncol = length(swgDates)))
o3 <- as.data.frame(matrix(nrow = length(nyears), ncol = length(swgDates)))
o4 <- as.data.frame(matrix(nrow = length(nyears), ncol = length(swgDates)))
o5 <- as.data.frame(matrix(nrow = length(nyears), ncol = length(swgDates)))

#cname <-   c("AMA", "BRE", "HUE", "POD", "YUN")

colnames(o0) <- colnames(o1) <- colnames(o2) <- colnames(o3) <- colnames(o4) <- colnames(o5) <- swgDates
rownames(o0) <- rownames(o1) <- rownames(o2) <- rownames(o3) <- rownames(o4) <- rownames(o5) <- nyears

for(i in 1:length(nyears)){
  
  for(j in 1:length(swgDates)){
    
    swg <- swgDates[j]
    weather <- wdata
    sowing <- paste(nyears[i], month(swg), day(swg), sep = "-")
    sowing <- as.Date(sowing)
    #harvest <- paste(nyears[i]+1, month(hvt), day(hvt), sep = "-")
    harvest <- as.Date(sowing) + hvtDAP
    plantDensity = 3.33
    #k=2.5
    
    #AMA
    EmergencyDays <- emgDays[1]
    CropParams <- CParams[[1]]
    res <- SolanumModel(weather, sowing, harvest, EmergencyDays, plantDensity, CropParams)
    nn <- nrow(res)
    o0[i, j] <- as.character(res$date[1])
    o1[i, j] <- round(res$fty[nn], 1)*runif(1,0.85,1.15)*3.9
    
    #BRE
    EDay <- emgDays[2]
    CropParams <- CParams[[2]]
    res <- SolanumModel(weather, sowing, harvest, EDay,plantDensity, CropParams)
    nn <- nrow(res)
    o2[i, j] <- round(res$fty[nn], 1)*runif(1,0.85,1.15)*5.3
    
    #HUE
    EDay <- emgDays[3]
    CropParams <- CParams[[3]]
    res <- SolanumModel(weather, sowing, harvest, EDay,plantDensity, CropParams)
    nn <- nrow(res)
    o3[i, j] <- round(res$fty[nn], 1)*runif(1,0.85,1.15)*4.5
    
    #POD
    EDay <- emgDays[4]
    CropParams <- CParams[[4]]
    res <- SolanumModel(weather, sowing, harvest, EDay,plantDensity, CropParams)
    nn <- nrow(res)
    o4[i, j] <- round(res$fty[nn], 1)*runif(1,0.85,1.15)*4.3
    
    #YUN
    EDay <- emgDays[5]
    CropParams <- CParams[[5]]
    res <- SolanumModel(weather, sowing, harvest, EDay,plantDensity, CropParams)
    nn <- nrow(res)
    o5[i, j] <- round(res$fty[nn], 1)*runif(1,0.85,1.15)*3.2
  }
}


FTYmean <- apply(outFTY[,2:6],2,max,na.rm=TRUE)
#apply(o1,2,mean)

outYP <- list(AMA = o1, BRE = o2, HUE = o3, POD = o4, YUN = o5)

oPD <- c("2020-08-15","2020-08-20","2020-08-25")
#oPD <- c("2020-09-25")

aPD <- c("2020-03-20","2020-03-25","2020-03-30","2020-04-05","2020-04-10",
         "2020-09-05","2020-09-10","2020-09-15","2020-09-20","2020-09-25")

#aPD <- c("2020-09-05","2020-09-10","2020-09-15","2020-09-20","2020-09-25")

### YPa: Optimum planting date & highest hielding variety
ypa <- outYP$AMA[,oPD]
ypa <- unlist(ypa)
YPa_mean <- mean(ypa)
YPa_se <- sd(ypa)/sqrt(length(ypa))

### YPb: actual planting date & highest hielding variety
ypb <- outYP$AMA[,aPD]
ypb <- unlist(ypb)
YPb_mean <- mean(ypb)
YPb_se <- sd(ypb)/sqrt(length(ypb))

### YPc: actual planting date & actual variety
a1 <- outYP$AMA[,aPD]
a2 <- outYP$BRE[,aPD]
a3 <- outYP$HUE[,aPD]
a4 <- outYP$POD[,aPD]
a5 <- outYP$YUN[,aPD]

ypc <- c(unlist(a1),unlist(a2),unlist(a3),unlist(a4),unlist(a5))
YPc_mean <- mean(ypc)
YPc_se <- sd(ypc)/sqrt(length(ypc))

means=c(YPa_mean,YPb_mean,YPc_mean)
stderr=c(YPa_se,YPb_se,YPc_se)

# Plot Potential yields
bp=barplot(means, las=1, ylim=c(0,80), col=c("blue","red","green"),
           names.arg=c("YPa", "YPb", "YPc"), ylab="Potential yield levels (t/ha)")

arrows(x0 = bp, y0 = means - stderr, x1 = bp, y1 = means + stderr, 
       angle = 90, code = 3, length = 0.1, col = "black")

Survey data collection

################################################################################
## 3. Thermal time computing
##################################################################################
#year0 = 2000
#year1 = 2022
#n <- as.Date("2023-01-31")-as.Date("2022-11-01")+1
#m <- year1-year0+1
#
##wdata <- wdata[wdata$YEAR>=year0 & #wdata$YEAR<=year1,]
#
#out0 <- as.data.frame(matrix(nrow = n, ncol = m))
#out1 <- as.data.frame(matrix(nrow = n, ncol = m))
#out2 <- as.data.frame(matrix(nrow = n, ncol = m))
#yy = seq(year0, year1, by = 1)
#
## load extra functions
#
#
#
#
#weather <- wdata
#
##for(jj in 1:m){
##  
##  date0 = as.Date(paste0(yy[jj], "-11-01"))-1
##  
##  for(ii in 1:n){
##  
##    
##    sDate = as.Date(date0 + ii)
##    sDate.name = paste(month(sDate), day(sDate), sep #= "-")
##    out0[ii, jj] = as.character(sDate)
##    
##    sowing = sDate
##    harvest = sowing + 90
##    ndays = as.numeric(harvest-sowing)+1
##    
#### variety Bari Alu 72    
##    source("https://raw.githubusercontent.com/jninany#a/Ramirez-et-a#l-2024/main/solanumR/BARI-Alu-72.R")
##    source("https://raw.githubusercontent.com/jninany#a/Ramirez-et-a#l-2024/main/solanumR/Module_PotentialGr#owth_V2.0.R")
##    
##    out1[ii, jj] = ifelse(df$fty[ndays]>20, #df$fty[ndays], NA)
##    
#### variety Bari Alu 78
##    source("https://raw.githubusercontent.com/jninany#a/Ramirez-et-a#l-2024/main/solanumR/BARI-Alu-78.R")
##    source("https://raw.githubusercontent.com/jninany#a/Ramirez-et-a#l-2024/main/solanumR/Module_PotentialGr#owth_V2.0.R")
##    
##    out2[ii, jj] = ifelse(df$fty[ndays]>20, #df$fty[ndays], NA)
##    
##    rownames(out0)[ii] = sDate.name
##    rownames(out1)[ii] = sDate.name
##    rownames(out2)[ii] = sDate.name
##  }
##  
##  colnames(out0)[jj] = yy[jj]
##  colnames(out1)[jj] = yy[jj]
##  colnames(out2)[jj] = yy[jj]
##  
##}
#
##d1 <- out1
##d2 <- out2
##
##boxplot(t(d1), col = "green", outline = FALSE, las=1,
##        ylab = "potential yield (t/ha)")
##
##boxplot(t(d2), col = "red", outline = FALSE, las=1,
##        ylab = "potential yield (t/ha)")
##
##
#### plot fty by planting date
##x <- 1:92
##fty_mean <- apply(out1, 1, mean, na.rm = TRUE)
##fty_q10 <- apply(out1, 1, quantile, probs = 0.10, #na.rm = TRUE)
##fty_q90 <- apply(out1, 1, quantile, probs = 0.90, #na.rm = TRUE)
##
##
###--------------------------------------------------
###--------------------------------------------------
##### General figure settings
##par(oma = c(4, 1, 0.5, 0.5),  # general margins
##    mfrow = c(2, 1),              # number of #sub-figures
##    mar = c(0,3,0,0),           # margins per #sub-figure
###    ps = 10,                      # text font size
##    family = "serif"              # text family
###    lwd = 0.5,                    # line width
###    las = 1,                      # style of axis #labels
###    pch = 20                      # plotting points
##)
##
##x=1:90
##y1=d1$`2021`[1:90]
##y2=d2$`2021`[1:90]
##plot(x, y1, type = "l", xlim = c(1,92), ylim = #c(23,57), 
##     xlab = "", ylab = "potential yield (t/ha)", axes #= FALSE, 
##     lwd = 2)
##box()
##lines(x, y2, lwd = 2, col = "gray50")
##
###axis(1, at = c(5,15,25,35,45,55,66,76,86), las = 2,
###     labels = #c("5-nov","15-nov","25-nov","5-dec","15-dec","25-dec#"#,"5-jan","15-jan","25-jan"))
###axis(1, las = 1, at = seq(5, 90, by=10))
##axis(2, las = 1, at=seq(25,55,by=5))
##abline(v=50, lty = 2, col = "blue")
##abline(v=74, lty = 2, col = "blue")
##
##text(47, 55.5, "ZT", col = "blue")
##text(71, 55.5, "CT", col = "blue")
##
##text(0, 55.5, expression(bold("A")))
##mtext(side=2, text=bquote("yield (t ha"^{"-1"}*")"), #cex = 1.5, #line = 2.4)
##
#####
##x=1:85
##y1=d1$`2022`[1:85]
##y2=d2$`2022`[1:85]
##plot(x, y1, type = "l", xlim = c(1,92), ylim = #c(23,52), 
##     xlab = "", ylab = "potential yield (t/ha)", axes #= FALSE, 
##     lwd = 2)
##box()
##lines(x, y2, lwd = 2, col = "gray50")
##
##axis(1, at = c(5,15,25,35,45,55,66,76,86), las = 2,
##     labels = #c("05-nov","15-nov","25-nov","05-dec","15-dec","25-de#c","05-jan","15-jan","25-jan"))
##axis(1, las = 1, at = seq(5, 90, by=10))
#axis(2, las = 1, at=seq(25,50,by=5))
#abline(v=44, lty = 2, col = "blue")
#abline(v=62, lty = 2, col = "blue")
#
#text(41, 51, "ZT", col = "blue")
#text(59, 51, "CT", col = "blue")
#
#text(0, 51, expression(bold("B")))
#
#mtext(side=2, text=bquote("yield (t ha"^{"-1"}*")"), cex = 1.5, #line = 2.4)
#

Stochastic Frontier Analysis

LS0tDQp0aXRsZTogIkRlY29tcG9zaXRpb24gb2YgcG90YXRvIHlpZWxkIGdhcCBpbiB0aGUgQW5kZWFuIG5vcnRoIG9mIFBlcnUiDQpzdWJ0aXRsZTogIkEgY3JvcCBtb2RlbGluZyBhcHByb2FjaCINCmF1dGhvcjogIkpvaGFuIE5pbmFueWEgKG5vbmkpIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0KI3NpdGU6IGJvb2tkb3duOjpib29rZG93bl9zaXRlDQojZG9jdW1lbnRjbGFzczogYm9vaw0Kb3V0cHV0Og0KICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoNCiAgICBoaWdobGlnaHQ6IGthdGUNCiAgICBudW1iZXJfc2VjdGlvbnM6IEZBTFNFDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCmBgYA0KDQojIyBCYWNrZ3JvdW5kDQoNClRoaXMgcmVwb3NpdG9yeSBpcyBkZXNpZ25lZCB0byBwcm92aWRlIGNvbXByZWhlbnNpdmUgZG9jdW1lbnRhdGlvbiBvZiB0aGUgUiBjb2RlIHVzZWQgZm9yIHRoZSBhbmFseXNpcyBvZiB5aWVsZCBnYXAgZGVjb21wb3NpdGlvbiwgaW50ZWdyYXRpbmcgYm90aCBjcm9wIG1vZGVsaW5nIGFuZCBzdG9jaGFzdGljIGZyb250aWVyIGFuYWx5c2lzLg0KDQoNCiMjIExpYnJhcmllcyBhbmQgZXh0cmEgUi1maWxlcw0KDQpUaGUgZm9sbG93aW5nIGxpYnJhcmllcyB3ZXJlIHVzZWQ6DQoNCmBgYHtyfQ0KIyBsaWJyYXJpZXMNCmxpYnJhcnkobmFzYXBvd2VyKQ0KbGlicmFyeShtZXRlb3IpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoTWV0cmljcykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShtaW5wYWNrLmxtKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCkFkZGl0aW9uYWxseSwgZXh0cmEgUi1maWxlcyBuZWVkIHRvIGJlIGxvYWRlZC4gDQoNCmBgYHtyfQ0KIyBleHRyYSBSLWZpbGVzDQpsb2FkKHVybCgiaHR0cHM6Ly9naXRodWIuY29tL2puaW5hbnlhL3NvbGFudW1SL3Jhdy9yZWZzL2hlYWRzL21haW4vQ3JvcFBhcmFtc0xpc3QuUmRhdGEiKSkNCnNvdXJjZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2puaW5hbnlhL3NvbGFudW1SL3JlZnMvaGVhZHMvbWFpbi90aGVybWFsVGltZS5SIikNCnNvdXJjZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2puaW5hbnlhL3NvbGFudW1SL3JlZnMvaGVhZHMvbWFpbi9Tb2xhbnVtTW9kZWwuUiIpDQoNCmBgYA0KDQoNCiMjIEZpZWxkIGV4cGVyaW1lbnQgYW5kIGRhdGEgY29sbGVjdGlvbg0KDQpBIGZpZWxkIGV4cGVyaW1lbnQgd2FzIGNvbmR1Y3RlZCB0byBkZXRlcm1pbmUgdGhlIHBvdGVudGlhbCB5aWVsZCBvZiB0aGUgZml2ZSBtb3N0IGNvbW1vbmx5IGdyb3duIHBvdGF0byB2YXJpZXRpZXMgaW4gQ2h1Z2F5LCBMYSBMaWJlcnRhZCwgUGVydTogQW1hcmlsbGlzLCBCcmV0YcOxYSwgSHVldm8gZGUgSW5kaW8sIFBvZGVyb3NhLCBhbmQgWXVuZ2F5LiBUaGVzZSB2YXJpZXRpZXMgd2VyZSBtYW5hZ2VkIHVuZGVyIG9wdGltYWwgZ3Jvd2luZyBjb25kaXRpb25zIHRvIGFzc2VzcyB0aGVpciB5aWVsZCBwb3RlbnRpYWwuIFRoZSB0cmlhbCB0b29rIHBsYWNlIGZyb20gMjR0aCBPY3RvYmVyIDIwMjMgdG8gMTh0aCBBcHJpbCAyMDI0LCBwcm92aWRpbmcgaW5zaWdodHMgaW50byBob3cgdGhlc2UgdmFyaWV0aWVzIHBlcmZvcm0gaW4gYSBsb2NhbCBjb250ZXh0IHVuZGVyICJpZGVhbCIgY29uZGl0aW9ucy4NCg0KPCEtLSBGaWd1cmUgMDEgLS0+DQo8YSBpZD0iRmlndXJlMDEiPjwvYT4NCjxkaXYgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyOyI+DQogICFbKipGaWd1cmEgMToqKiBGaWVsZCBleHBlcmltZW50IHRvIGRldGVybWluZSBwb3RlbnRpYWwgeWllbGQgb2YgdGhlIG1vc3QgY29tbW9uIHBvdGF0byB2YXJpZXRpZXMgaW4gQ2h1Z2F5IERpc3RyaWMsIExhLUxpYmVydGFkIHJlZ2lvbiwgUGVydS5dKGh0dHBzOi8vZ2l0aHViLmNvbS9qbmluYW55YS9Qb3RhdG9fWWllbGRfR2FwL2Jsb2IvbWFpbi9GaWd1cmVzL0ZpZWxkX2V4cGVyaW1lbnQucG5nP3Jhdz10cnVlKXt3aWR0aD04MSV9DQogIDxwIHN0eWxlPSJtYXJnaW4tYm90dG9tOiAxMHB4OyI+PC9wPiA8IS0tIEFkZCBzb21lIHNwYWNlIGJlbG93IHRoZSBpbWFnZSBjYXB0aW9uIC0tPg0KPC9kaXY+DQoNCkEgdG90YWwgb2YgZml2ZSBiaW9tYXNzIGV2YWx1YXRpb25zIHdlcmUgY2FycmllZCBvdXQsIHdoZXJlIHRoZSBwbGFudCBvcmdhbnMgKGxlYWYsIHN0ZW0sIHJvb3QsIGFuZCB0dWJlcnMpIHdlcmUgc2VwYXJhdGVkLCBldmVyeSB0d28gd2Vla3MgZnJvbSB0aGUgdHViZXJpemF0aW9uIHN0YWdlIHRvIGhhcnZlc3QuIEFkZGl0aW9uYWxseSwgZmlmdGVlbiBjYW5vcHkgY292ZXIgZXZhbHVhdGlvbnMgd2VyZSBjb25kdWN0ZWQgZnJvbSBwbGFudCBlbWVyZ2VuY2UgdG8gc2VuZXNjZW5jZSwgcHJvdmlkaW5nIGRldGFpbGVkIGRhdGEgb24gdGhlIGdyb3d0aCBhbmQgZGV2ZWxvcG1lbnQgb2YgdGhlIGZpdmUgcG90YXRvIHZhcmlldGllcy4gVGhlIGRhdGFzZXQgcmVsYXRlZCB0byB0aGlzIGZpZWxkIGV4cGVyaW1lbnQgY2FuIGJlIGRvd25sb2FkZWQgYXQgaHR0cHM6Ly9kb2kub3JnLzEwLjIxMjIzL0pQQTNOWi4gDQoNCiMjIyBCaW9tYXNzIGRhdGENCkxldHMgc2VlIHRoZSBoYXJ2ZXN0IGluZGV4LCBpLmUuLCB0aGUgcmF0aW8gb2YgdHViZXIgYmlvbWFzcyBvdmVyIHRvdGFsIGJpb21hc3MuIENsaWNrIG9uIGBjb2RlYCB0byBzZWUgdGhlIFIgY2h1bmsgY29kZSBmb3IgdGhlIGNhbm9weSBiaW9tYXNzIGRhdGEuDQoNCmBgYHtyICBjbGFzcy5zb3VyY2U9J2ZvbGQtaGlkZScsIHJlc3VsdHM9J2hvbGQnLCBmaWcud2lkdGg9OSxmaWcuaGVpZ2h0PTIuNX0NCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgU1VNTUFSWSBPRiBCSU9NQVNTIERBVEENCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCkJEIDwtIHJlYWQuY3N2KCJodHRwczovL2dpdGh1Yi5jb20vam5pbmFueWEvUG90YXRvX1lpZWxkX0dhcC9yYXcvcmVmcy9oZWFkcy9tYWluL0RhdGEvYmlvbWFzc19kYXRhc2V0LmNzdiIpDQojaGVhZChCRCkNCg0KIyBDb25zdGFudCB0byBjb252ZXJ0IGtnL3BsYW50IHRvIHQvaGENCmsgPSAoMS8xMDAwKSooMS8oMC4zKjEpKSooMTAwMDAvMSkqMC4wMDENCg0KIyBNYXR0ZXIgY29uY2VudHJhdGlvbiBvZiA8b3JnYW4+IChNQ1gpDQpCRCRNQ0wgPC0gQkQkc0RMTS9CRCRzRkxNICAgICAgIyBMID0gbGVhZg0KQkQkTUNTIDwtIEJEJHNEU00vQkQkc0ZTTSAgICAgICMgUyA9IHN0ZW0NCkJEJE1DUiA8LSBCRCRzRFJNL0JEJHNGUk0gICAgICAjIFIgPSByb290DQpCRCRNQ1QgPC0gQkQkc0RUTS9CRCRzRlRNICAgICAgIyBUID0gdHViZXINCkJEJERNQyA8LSBCRCRNQ1QgICAgICAgICAgICAgICAgIA0KDQojIERyeSA8b3JnYW4+IG1hdHRlciAoRFhNKQ0KQkQkRExNIDwtIEJEJEZMTSpCRCRNQ0wNCkJEJERTTSA8LSBCRCRGU00qQkQkTUNTDQpCRCREUk0gPC0gQkQkRlJNKkJEJE1DUg0KQkQkRFRNIDwtIEJEJEZUTSpCRCRNQ1QNCg0KIyBGcmVzaCA8b3JnYW4+IHlpZWxkIChGWFkpDQpCRCRGTFkgPC0gQkQkRkxNKmsNCkJEJEZTWSA8LSBCRCRGU00qaw0KQkQkRlJZIDwtIEJEJEZSTSprDQpCRCRGVFkgPC0gQkQkRlRNKmsgICAgICAgICAgICAgICANCg0KIyBEcnkgPG9yZ2FuPiB5aWVsZCAoRFhZKQ0KQkQkRExZIDwtIEJEJERMTSprDQpCRCREU1kgPC0gQkQkRFNNKmsNCkJEJERSWSA8LSBCRCREUk0qaw0KQkQkRFRZIDwtIEJEJERUTSprDQoNCiMgVG90YWwgZHJ5IG1hdHRlciAoVERNKSBhbmQgaGFydmVzdCBpbmRleCAoSEkpDQpCRCRURE0gPC0gQkQkRExZICsgQkQkRFNZICsgQkQkRFJZICsgQkQkRFRZDQpCRCRISSA8LSBCRCREVFkvQkQkVERNDQoNCiMgU3VtbWFyeTogbWVhbiBhbmQgc3RhbmRhcmQgZXJyb3IgZm9yIEhJDQpzbXJCRCA8LSBCRCAlPiUNCiAgZ3JvdXBfYnkoQ09ERSwgRVZBTCwgREFQKSAlPiUNCiAgc3VtbWFyaXNlKERMWSA9IG1lYW4oRExZLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgRFNZID0gbWVhbihEU1ksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBEUlkgPSBtZWFuKERSWSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIERUWSA9IG1lYW4oRFRZLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgRlRZID0gbWVhbihGVFksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBURE0gPSBtZWFuKFRETSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIERNQyA9IG1lYW4oRE1DLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgTiA9IHN1bSghaXMubmEoSEkpKSwNCiAgICAgICAgICAgIG5kID0gbigpLA0KICAgICAgICAgICAgSElfbWVhbiA9IG1lYW4oSEksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBISV9zZSA9IHNkKEhJLCBuYS5ybSA9IFRSVUUpL3NxcnQoTikNCiAgICApDQpzbXJCRCA8LSBhcy5kYXRhLmZyYW1lKHNtckJEKQ0KDQpvdXRCRCA8LSBzbXJCRFssIGMoIkNPREUiLCJEQVAiLCJISV9tZWFuIildICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ09ERSwgdmFsdWVzX2Zyb20gPSBISV9tZWFuKQ0Kb3V0QkQNCg0Kb3V0VERNIDwtIHNtckJEWywgYygiQ09ERSIsIkRBUCIsIlRETSIpXSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IENPREUsIHZhbHVlc19mcm9tID0gVERNKQ0Kb3V0VERNIDwtIGFzLmRhdGEuZnJhbWUob3V0VERNKQ0KDQpvdXRETUMgPC0gc21yQkRbLCBjKCJDT0RFIiwiREFQIiwiRE1DIildICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gQ09ERSwgdmFsdWVzX2Zyb20gPSBETUMpDQpvdXRETUMgPC0gYXMuZGF0YS5mcmFtZShvdXRETUMpDQoNCm91dEZUWSA8LSBzbXJCRFssIGMoIkNPREUiLCJEQVAiLCJGVFkiKV0gJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBDT0RFLCB2YWx1ZXNfZnJvbSA9IEZUWSkNCm91dEZUWSA8LSBhcy5kYXRhLmZyYW1lKG91dEZUWSkNCg0KIyBEYXRhIGZyYW1lIGZvciBlYWNoIHZhcmlldHkNCkFNQSA8LSBzbXJCRFtzbXJCRCRDT0RFPT0iQU1BIixdDQpCUkUgPC0gc21yQkRbc21yQkQkQ09ERT09IkJSRSIsXQ0KSFVFIDwtIHNtckJEW3NtckJEJENPREU9PSJIVUUiLF0NClBPRCA8LSBzbXJCRFtzbXJCRCRDT0RFPT0iUE9EIixdDQpZVU4gPC0gc21yQkRbc21yQkQkQ09ERT09IllVTiIsXQ0KDQojIEdlbmVyYWwgcGxvdCBzZXR0aW5ncw0KcGFyKG9tYSAgICA9IGMoNC41LCA0LjUsIDAuNSwgMyksICAjIGdlbmVyYWwgbWFyZ2lucw0KICAgIG1mcm93ICA9IGMoMSwgNSksICAgICAgICAgICAgICAgICMgbnVtYmVyIG9mIHN1Yi1maWd1cmVzDQogICAgbWFyICAgID0gYygwLCAwLCAwLCAwKSwgICAgICAgICAgIyBtYXJnaW5zIHBlciBzdWItZmlndXJlDQogICAgZmFtaWx5ID0gInNlcmlmIiwgICAgICAgICAgICAgICAgIyB0ZXh0IGZhbWlseQ0KICAgIGx3ZCAgICA9IDEuMCwgICAgICAgICAgICAgICAgICAgICMgbGluZSB3aWR0aA0KICAgIGxhcyAgICA9IDEsICAgICAgICAgICAgICAgICAgICAgICMgc3R5bGUgb2YgYXhpcyBsYWJlbHMgIA0KICAgIHBjaCAgICA9IDE5LCAgICAgICAgICAgICAgICAgICAgICMgcGxvdHRpbmcgcG9pbnRzDQogICAgY2V4ICAgID0gMC44DQopDQoNCiMgQ29sb3IgYW5kIHktYXhpcyBsaW1pdHMNCnBDIDwtIGMoImJsdWUiLCJ5ZWxsb3ciLCJncmVlbiIsImN5YW4iLCJyZWQiKSANCnlMIDwtIGMoMCwxKSANCg0KIyBQbG90IGZvciBBbWFyaWxpcw0Kd2l0aChBTUEsIHBsb3QoeD1EQVAsIHk9SElfbWVhbiwgeWxpbT15TCwgY29sPXBDWzFdLCBheGVzPUZBTFNFLCB4bGFiPSIiLCB5bGFiPSIiKSkNCndpdGgoQU1BLCBsaW5lcyh4PURBUCwgeT1ISV9tZWFuLCBsdHk9MiwgY29sPXBDWzFdKSkNCmJveCgpOyBheGlzKDIpOyBheGlzKDQsIGxhYmVscz1GQUxTRSk7YXhpcygxKQ0KbXRleHQoc2lkZT0yLCAiSGFydmVzdCBJbmRleCIsIGxpbmU9MywgbGFzPTApDQoNCiMgUGxvdCBmb3IgQnJldGFuYQ0Kd2l0aChCUkUsIHBsb3QoeD1EQVAsIHk9SElfbWVhbiwgeWxpbT15TCwgY29sPXBDWzJdLCBheGVzPUZBTFNFLCB4bGFiPSIiLCB5bGFiPSIiKSkNCndpdGgoQlJFLCBsaW5lcyh4PURBUCwgeT1ISV9tZWFuLCBsdHk9MiwgY29sPXBDWzJdKSkNCmJveCgpOyBheGlzKDIsbGFiZWxzPUZBTFNFKTsgYXhpcyg0LCBsYWJlbHM9RkFMU0UpO2F4aXMoMSkNCg0KIyBQbG90IGZvciBIdWV2byBkZSBJbmRpbw0Kd2l0aChIVUUsIHBsb3QoeD1EQVAsIHk9SElfbWVhbiwgeWxpbT15TCwgY29sPXBDWzNdLCBheGVzPUZBTFNFLCB4bGFiPSIiLCB5bGFiPSIiKSkNCndpdGgoSFVFLCBsaW5lcyh4PURBUCwgeT1ISV9tZWFuLCBsdHk9MiwgY29sPXBDWzNdKSkNCmJveCgpOyBheGlzKDIsbGFiZWxzPUZBTFNFKTsgYXhpcyg0LCBsYWJlbHM9RkFMU0UpO2F4aXMoMSkNCm10ZXh0KHNpZGU9MSwgIkRheXMgYWZ0ZXIgcGxhbnRpbmciLCBsaW5lPTMpDQoNCiMgUGxvdCBmb3IgUG9kZXJvc2ENCndpdGgoUE9ELCBwbG90KHg9REFQLCB5PUhJX21lYW4sIHlsaW09eUwsIGNvbD1wQ1s0XSwgYXhlcz1GQUxTRSwgeGxhYj0iIiwgeWxhYj0iIikpDQp3aXRoKFBPRCwgbGluZXMoeD1EQVAsIHk9SElfbWVhbiwgbHR5PTIsIGNvbD1wQ1s0XSkpDQpib3goKTsgYXhpcygyLGxhYmVscz1GQUxTRSk7IGF4aXMoNCwgbGFiZWxzPUZBTFNFKTtheGlzKDEpDQoNCiMgUGxvdCBmb3IgWXVuZ2F5DQp3aXRoKFlVTiwgcGxvdCh4PURBUCwgeT1ISV9tZWFuLCB5bGltPXlMLCBjb2w9cENbNV0sIGF4ZXM9RkFMU0UsIHhsYWI9IiIsIHlsYWI9IiIpKQ0Kd2l0aChZVU4sIGxpbmVzKHg9REFQLCB5PUhJX21lYW4sIGx0eT0yLCBjb2w9cENbNV0pKQ0KYm94KCk7IGF4aXMoMixsYWJlbHM9RkFMU0UpOyBheGlzKDQpO2F4aXMoMSkNCg0KYGBgDQoNCiMjIyBDYW5vcHkgY292ZXIgZGF0YQ0KQ2xpY2sgb24gYGNvZGVgIHRvIHNlZSB0aGUgUiBjaHVuayBjb2RlIGZvciB0aGUgY2Fub3B5IGNvdmVyIGRhdGEuDQoNCmBgYHtyICBjbGFzcy5zb3VyY2U9J2ZvbGQtaGlkZScsIHJlc3VsdHM9J2hvbGQnLCBmaWcud2lkdGg9OSxmaWcuaGVpZ2h0PTIuNX0NCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgU1VNTUFSWSBPRiBDQU5PUFkgQ09WRVIgREFUQQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KQ0QgPC0gcmVhZC5jc3YoImh0dHBzOi8vZ2l0aHViLmNvbS9qbmluYW55YS9Qb3RhdG9fWWllbGRfR2FwL3Jhdy9yZWZzL2hlYWRzL21haW4vRGF0YS9jYW5vcHlfY292ZXJfZGF0YXNldC5jc3YiKQ0KI2hlYWQoQ0QpDQoNCiMgU3VtbWFyeSBieSB2YXJpZXR5IGFuZCBldmFsdWF0aW9uDQpzbXJDRCA8LSBDRCAlPiUNCiAgZ3JvdXBfYnkoQ09ERSwgREFQKSAlPiUNCiAgc3VtbWFyaXNlKE4gPSBzdW0oIWlzLm5hKENDKSksDQogICAgICAgICAgICBuZCA9IG4oKSwNCiAgICAgICAgICAgIENDX21lYW4gPSBtZWFuKENDLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgQ0Nfc2UgPSBzZChDQywgbmEucm0gPSBUUlVFKS9zcXJ0KE4pLA0KICApDQoNCnNtckNEIDwtIGFzLmRhdGEuZnJhbWUoc21yQ0QpDQoNCiMgRGF0YSBmcmFtZSBwZXIgdmFyaWV0eQ0Kb3V0Q0QgPC0gc21yQ0RbLCBjKCJDT0RFIiwiREFQIiwiQ0NfbWVhbiIpXSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IENPREUsIHZhbHVlc19mcm9tID0gQ0NfbWVhbikNCm91dENEDQoNCiMgRGF0YSBmcmFtZSBmb3IgZWFjaCB2YXJpZXR5DQpBTUEgPC0gc21yQ0Rbc21yQ0QkQ09ERT09IkFNQSIsXQ0KQlJFIDwtIHNtckNEW3NtckNEJENPREU9PSJCUkUiLF0NCkhVRSA8LSBzbXJDRFtzbXJDRCRDT0RFPT0iSFVFIixdDQpQT0QgPC0gc21yQ0Rbc21yQ0QkQ09ERT09IlBPRCIsXQ0KWVVOIDwtIHNtckNEW3NtckNEJENPREU9PSJZVU4iLF0NCg0KIyBHZW5lcmFsIHBsb3Qgc2V0dGluZ3MNCnBhcihvbWEgICAgPSBjKDQuNSwgNC41LCAwLjUsIDMpLCAgIyBnZW5lcmFsIG1hcmdpbnMNCiAgICBtZnJvdyAgPSBjKDEsIDUpLCAgICAgICAgICAgICAgICAjIG51bWJlciBvZiBzdWItZmlndXJlcw0KICAgIG1hciAgICA9IGMoMCwgMCwgMCwgMCksICAgICAgICAgICMgbWFyZ2lucyBwZXIgc3ViLWZpZ3VyZQ0KICAgIGZhbWlseSA9ICJzZXJpZiIsICAgICAgICAgICAgICAgICMgdGV4dCBmYW1pbHkNCiAgICBsd2QgICAgPSAxLjAsICAgICAgICAgICAgICAgICAgICAjIGxpbmUgd2lkdGgNCiAgICBsYXMgICAgPSAxLCAgICAgICAgICAgICAgICAgICAgICAjIHN0eWxlIG9mIGF4aXMgbGFiZWxzICANCiAgICBwY2ggICAgPSAxOSwgICAgICAgICAgICAgICAgICAgICAjIHBsb3R0aW5nIHBvaW50cw0KICAgIGNleCAgICA9IDAuOA0KKQ0KDQojIENvbG9yIGFuZCB5LWF4aXMgbGltaXRzDQpwQyA8LSBjKCJibHVlIiwieWVsbG93IiwiZ3JlZW4iLCJjeWFuIiwicmVkIikgDQp5TCA8LSBjKDAsMTAwKSANCg0KIyBQbG90IGZvciBBbWFyaWxpcw0Kd2l0aChBTUEsIHBsb3QoeD1EQVAsIHk9Q0NfbWVhbiwgeWxpbT15TCwgY29sPXBDWzFdLCBheGVzPUZBTFNFLCB4bGFiPSIiLCB5bGFiPSIiKSkNCndpdGgoQU1BLCBsaW5lcyh4PURBUCwgeT1DQ19tZWFuLCBsdHk9MiwgY29sPXBDWzFdKSkNCmJveCgpOyBheGlzKDIpOyBheGlzKDQsIGxhYmVscz1GQUxTRSk7YXhpcygxKQ0KbXRleHQoc2lkZT0yLCAiQ2Fub3B5IGNvdmVyICglKSIsIGxpbmU9MywgbGFzPTApDQoNCiMgUGxvdCBmb3IgQnJldGFuYQ0Kd2l0aChCUkUsIHBsb3QoeD1EQVAsIHk9Q0NfbWVhbiwgeWxpbT15TCwgY29sPXBDWzJdLCBheGVzPUZBTFNFLCB4bGFiPSIiLCB5bGFiPSIiKSkNCndpdGgoQlJFLCBsaW5lcyh4PURBUCwgeT1DQ19tZWFuLCBsdHk9MiwgY29sPXBDWzJdKSkNCmJveCgpOyBheGlzKDIsbGFiZWxzPUZBTFNFKTsgYXhpcyg0LCBsYWJlbHM9RkFMU0UpO2F4aXMoMSkNCg0KIyBQbG90IGZvciBIdWV2byBkZSBJbmRpbw0Kd2l0aChIVUUsIHBsb3QoeD1EQVAsIHk9Q0NfbWVhbiwgeWxpbT15TCwgY29sPXBDWzNdLCBheGVzPUZBTFNFLCB4bGFiPSIiLCB5bGFiPSIiKSkNCndpdGgoSFVFLCBsaW5lcyh4PURBUCwgeT1DQ19tZWFuLCBsdHk9MiwgY29sPXBDWzNdKSkNCmJveCgpOyBheGlzKDIsbGFiZWxzPUZBTFNFKTsgYXhpcyg0LCBsYWJlbHM9RkFMU0UpO2F4aXMoMSkNCm10ZXh0KHNpZGU9MSwgIkRheXMgYWZ0ZXIgcGxhbnRpbmciLCBsaW5lPTMpDQoNCiMgUGxvdCBmb3IgUG9kZXJvc2ENCndpdGgoUE9ELCBwbG90KHg9REFQLCB5PUNDX21lYW4sIHlsaW09eUwsIGNvbD1wQ1s0XSwgYXhlcz1GQUxTRSwgeGxhYj0iIiwgeWxhYj0iIikpDQp3aXRoKFBPRCwgbGluZXMoeD1EQVAsIHk9Q0NfbWVhbiwgbHR5PTIsIGNvbD1wQ1s0XSkpDQpib3goKTsgYXhpcygyLGxhYmVscz1GQUxTRSk7IGF4aXMoNCwgbGFiZWxzPUZBTFNFKTtheGlzKDEpDQoNCiMgUGxvdCBmb3IgWXVuZ2F5DQp3aXRoKFlVTiwgcGxvdCh4PURBUCwgeT1DQ19tZWFuLCB5bGltPXlMLCBjb2w9cENbNV0sIGF4ZXM9RkFMU0UsIHhsYWI9IiIsIHlsYWI9IiIpKQ0Kd2l0aChZVU4sIGxpbmVzKHg9REFQLCB5PUNDX21lYW4sIGx0eT0yLCBjb2w9cENbNV0pKQ0KYm94KCk7IGF4aXMoMixsYWJlbHM9RkFMU0UpOyBheGlzKDQpO2F4aXMoMSkNCg0KYGBgDQoNCg0KIyMgQmlhc3MgY29ycmVjdGlvbiBvZiB3ZWF0aGVyIGRhdGENCkEgYmlhcyBjb3JyZWN0aW9uIG9mIE5BU0FQb3dlciB3ZWF0aGVyIGRhdGEgd2FzIHBlcmZvcm1lZCB1c2luZyBpbmZvcm1hdGlvbiBmcm9tIGFuIGluIHNpdHUgd2VhdGhlciBzdGF0aW9uLiBUaGUgY29ycmVjdGlvbiBtZXRob2RzIGFwcGxpZWQgaW5jbHVkZWQgbGluZWFyIHJlZ3Jlc3Npb24sIHF1YW50aWxlIG1hdGNoaW5nLCBhbmQgc3RhdGlzdGljYWwgZGlzdHJpYnV0aW9uIHdpdGggc3BsaW5lIGN1Ymljcy4gQWx0aG91Z2ggdGhlIGluIHNpdHUgd2VhdGhlciBzdGF0aW9uIHByb3ZpZGVkIGRhdGEgZm9yIG9ubHkgb25lIHllYXIsIGEgMTAteWVhciB3ZWF0aGVyIGRhdGFzZXQgd2FzIGdlbmVyYXRlZCB1c2luZyB0aGUgYmlhcy1jb3JyZWN0ZWQgTkFTQVBvd2VyIGRhdGEgKHRvIGF2b2lkIHNlYXNvbmFsaXR5IGVycm9yKSwgZW5zdXJpbmcgaXQgYWNjdXJhdGVseSByZWZsZWN0cyBsb2NhbCBjb25kaXRpb25zIGR1cmluZyB0aGUgZXhwZXJpbWVudC4NCg0KQSBzaW1wbGUgYmlhcyBjb3JyZWN0aW9uIHdhcyBjaG9zZW4sIGFuZCB0aGUgbWluaW11bSB0ZW1wZXJhdHVyZSwgbWF4aW11bSB0ZW1wZXJhdHVyZSwgYW5kIHNvbGFyIHJhZGlhdGlvbiB3ZXJlIGNvcnJlY3RlZC4gSWYgeW91IHdvdWxkIGxpa2UgdG8gc2VlIHRoZSBjb2RlIGNodW5rLCBjbGljayBvbiBgY29kZWAuDQoNCmBgYHtyIGNsYXNzLnNvdXJjZT0nZm9sZC1oaWRlJywgcmVzdWx0cz0naG9sZCd9DQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIFJFVFJJRVZFIERBVEEgRlJPTSBOQVNBIFBPV0VSDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIERlZmluZSB2YXJpYWJsZXMgKHd2YXJzKSBhbmQgcGVyaW9kDQp3dmFycyA8LSBjKCJUMk1fTUFYIiwgIlQyTV9NSU4iLCAiQUxMU0tZX1NGQ19TV19EV04iKQ0KcGVyaW9kIDwtIGMoIjIwMDAtMDEtMDEiLCAiMjAyNC0wNS0zMSIpDQoNCiMgQ29vcmRpbmF0ZXMgKGxvbiwgbGF0KQ0KUFJPIDwtIGMoLTc3LjgyLCAtNy43NSkgDQoNCiMgR2V0IGRhaWx5IGRhdGEgZnJvbSBOQVNBIFBPV0VSIA0Kd2RhdGEgPC0gZ2V0X3Bvd2VyKA0KICBjb21tdW5pdHkgPSAiYWciLA0KICBsb25sYXQgPSBQUk8sDQogIHBhcnMgPSB3dmFycywNCiAgZGF0ZXMgPSBwZXJpb2QsDQogIHRlbXBvcmFsX2FwaSA9ICJkYWlseSINCikNCg0Kd2QgPC0gZGF0YS5mcmFtZShkYXRlID0gd2RhdGEkWVlZWU1NREQsIHRtaW4gPSB3ZGF0YSRUMk1fTUlOLA0KICAgICAgICAgICAgICAgICB0bWF4ID0gd2RhdGEkVDJNX01BWCwgc3JhZCA9IHdkYXRhJEFMTFNLWV9TRkNfU1dfRFdOKQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIENPUlJFQ1QgREFUQSBGUk9NIE5BU0EgUE9XRVINCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgTG9jYWwgd2VhdGhlciBkYXRhDQpkZiA8LSByZWFkLmNzdigiaHR0cHM6Ly9naXRodWIuY29tL2puaW5hbnlhL1BvdGF0b19ZaWVsZF9HYXAvcmF3L3JlZnMvaGVhZHMvbWFpbi9EYXRhL2RhdGFzZXRfZm9yX21vZGVsX2NhbGlicmF0aW9uLmNzdiIpDQpjb2xuYW1lcyhkZikgPC0gdG9sb3dlcihjb2xuYW1lcyhkZikpDQoNCiMgR3Jvd2luZyBzZWFzb24NCnN3Z0RhdGUgPC0gYXMuRGF0ZSgiMjAyMy0xMC0yNCIpDQpodnREYXRlIDwtIGFzLkRhdGUoIjIwMjQtMDQtMTgiKQ0KR1MgPC0gc2VxKHN3Z0RhdGUsIGh2dERhdGUsIGJ5ID0gMSkNCg0Kd2RTIDwtIHdkW3dkJGRhdGUgPj0gc3dnRGF0ZSAmIHdkJGRhdGUgPD0gaHZ0RGF0ZSwgXQ0Kd2RPIDwtIGRmDQojc3VtKHdkUyRkYXRlID09IHdkTyRkYXRlKSA9PSBsZW5ndGgod2RPJGRhdGUpDQoNCiMgQ3JlYXRlIHNhbXBsZXMgZm9yIHRyYWluaW5nIGFuZCB2YWxpZGF0aW9uDQpzZXQuc2VlZCgzMzMpDQpuVCA8LSAxOm5yb3cod2RPKSAgICAgICAgICAgICAgICMgbiB0b3RhbA0KblMgPC0gcm91bmQoMC43MCpucm93KHdkTyksIDApICAjIG4gc2FtcGxlDQpUcGVyaW9kIDwtIHNhbXBsZShuVCwgblMpDQpWcGVyaW9kIDwtIG5UWy1UcGVyaW9kXQ0KDQojIFBlcmZvcm1hbmNlIG1ldHJpY3MNCm5NIDwtIDUNCk0xIDwtIG1hdHJpeChucm93ID0gbk0sIG5jb2wgPSAzKSAjIFJSTVNFDQpNMiA8LSBtYXRyaXgobnJvdyA9IG5NLCBuY29sID0gMykgIyBSTVNFDQpNMyA8LSBtYXRyaXgobnJvdyA9IG5NLCBuY29sID0gMykgIyBSMg0KTTQgPC0gbWF0cml4KG5yb3cgPSBuTSwgbmNvbCA9IDMpICMgbSAoc2xvcGUpDQoNCm91dEJDIDwtIGxpc3QoKSAgIyBCaWFzIENvcnJlY3Rpb24NCm91dExSIDwtIGxpc3QoKSAgIyBMaW5lYXIgUmVncmVzc2lvbg0Kb3V0UU0gPC0gbGlzdCgpICAjIFF1YW50aWxlIE1hdGNoaW5nDQpvdXRTRCA8LSBsaXN0KCkgICMgU3RhdGlzdGljYWwgRGlzdHJpYnV0aW9uDQoNCmZvcihpIGluIDE6Myl7DQogIA0KICBvYnNUID0gd2RPW1RwZXJpb2QsIDEraV0NCiAgc2ltVCA9IHdkU1tUcGVyaW9kLCAxK2ldDQogIA0KICBvYnNWID0gd2RPW1ZwZXJpb2QsIDEraV0NCiAgc2ltViA9IHdkU1tWcGVyaW9kLCAxK2ldDQogIA0KICAjIFdpdGhvdXQgYW55IGNvcnJlY3Rpb24NCiAgYWN0dWFsID0gb2JzVg0KICBwcmVkaWN0ZWQgPSBzaW1WDQogIFJFRyA9IHN1bW1hcnkobG0oYWN0dWFsIH4gcHJlZGljdGVkICsgMCkpDQogIE0xWzEsIGldID0gcm91bmQocm1zZShhY3R1YWwsIHByZWRpY3RlZCkvbWVhbihhY3R1YWwpKjEwMCwgMSkNCiAgTTJbMSwgaV0gPSByb3VuZChybXNlKGFjdHVhbCwgcHJlZGljdGVkKSwgMikNCiAgTTNbMSwgaV0gPSByb3VuZChSRUckYWRqLnIuc3F1YXJlZCwgMikNCiAgTTRbMSwgaV0gPSByb3VuZChSRUckY29lZmZpY2llbnRzWzEsMV0sIDIpDQogIA0KICAjIEJpYXMgY29ycmVjdGlvbg0KICBiaWFzID0gbWVhbihvYnNUIC0gc2ltVCkNCiAgb2JzQyA9IHNpbVYgKyBiaWFzDQogIGFjdHVhbCA9IG9ic1YNCiAgcHJlZGljdGVkID0gb2JzQw0KICBSRUcgPSBzdW1tYXJ5KGxtKGFjdHVhbCB+IHByZWRpY3RlZCArIDApKQ0KICBNMVsyLCBpXSA9IHJvdW5kKHJtc2UoYWN0dWFsLCBwcmVkaWN0ZWQpL21lYW4oYWN0dWFsKSoxMDAsIDEpDQogIE0yWzIsIGldID0gcm91bmQocm1zZShhY3R1YWwsIHByZWRpY3RlZCksIDIpDQogIE0zWzIsIGldID0gcm91bmQoUkVHJGFkai5yLnNxdWFyZWQsIDIpDQogIE00WzIsIGldID0gcm91bmQoUkVHJGNvZWZmaWNpZW50c1sxLDFdLCAyKQ0KICANCiAgIyBMaW5lYXIgcmVncmVzc2lvbg0KICBMUiA9IGxtKG9ic1QgfiBzaW1UKQ0KICBvYnNDID0gcHJlZGljdChMUiwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoc2ltVCA9IHNpbVYpKQ0KICBhY3R1YWwgPSBvYnNWDQogIHByZWRpY3RlZCA9IG9ic0MNCiAgUkVHID0gc3VtbWFyeShsbShhY3R1YWwgfiBwcmVkaWN0ZWQgKyAwKSkNCiAgTTFbMywgaV0gPSByb3VuZChybXNlKGFjdHVhbCwgcHJlZGljdGVkKS9tZWFuKGFjdHVhbCkqMTAwLCAxKQ0KICBNMlszLCBpXSA9IHJvdW5kKHJtc2UoYWN0dWFsLCBwcmVkaWN0ZWQpLCAyKQ0KICBNM1szLCBpXSA9IHJvdW5kKFJFRyRhZGouci5zcXVhcmVkLCAyKQ0KICBNNFszLCBpXSA9IHJvdW5kKFJFRyRjb2VmZmljaWVudHNbMSwxXSwgMikNCiAgDQogICMgUXVhbnRpbGUgbWF0Y2hpbmcNCiAgY29tbW9uX3F1YW50aWxlcyA9IHNlcSgwLCAxLCBsZW5ndGgub3V0ID0gMTAwKQ0KICBzQ0RGID0gcXVhbnRpbGUoc2ltVCwgcHJvYnMgPSBjb21tb25fcXVhbnRpbGVzKQ0KICBvQ0RGID0gcXVhbnRpbGUob2JzVCwgcHJvYnMgPSBjb21tb25fcXVhbnRpbGVzKQ0KICBRTSA9IGxtKG9DREYgfiBzQ0RGKQ0KICBvYnNDID0gc2ltVipjb2VmKFFNKVsyXSArIGNvZWYoUU0pWzFdDQogIGFjdHVhbCA9IG9ic1YNCiAgcHJlZGljdGVkID0gb2JzQw0KICBSRUcgPSBzdW1tYXJ5KGxtKGFjdHVhbCB+IHByZWRpY3RlZCArIDApKQ0KICBNMVs0LCBpXSA9IHJvdW5kKHJtc2UoYWN0dWFsLCBwcmVkaWN0ZWQpL21lYW4oYWN0dWFsKSoxMDAsIDEpDQogIE0yWzQsIGldID0gcm91bmQocm1zZShhY3R1YWwsIHByZWRpY3RlZCksIDIpDQogIE0zWzQsIGldID0gcm91bmQoUkVHJGFkai5yLnNxdWFyZWQsIDIpDQogIE00WzQsIGldID0gcm91bmQoUkVHJGNvZWZmaWNpZW50c1sxLDFdLCAyKQ0KICANCiAgIyBTdGF0aXN0aWNhbCBkaXN0cmlidXRpb24gd2l0aCBzbGluZSBjdWJpY3MgDQogIHNvcnRfb2JzID0gc29ydChvYnNUKQ0KICBzb3J0X3NpbSA9IHNvcnQoc2ltVCkNCiAgU0QgPSBzbW9vdGguc3BsaW5lKHNvcnRfc2ltLCBzb3J0X29icykNCiAgb2JzQyA9IHByZWRpY3QoU0QsIHNpbVYpJHkNCiAgYWN0dWFsID0gb2JzVg0KICBwcmVkaWN0ZWQgPSBvYnNDDQogIFJFRyA9IHN1bW1hcnkobG0oYWN0dWFsIH4gcHJlZGljdGVkICsgMCkpDQogIE0xWzUsIGldID0gcm91bmQocm1zZShhY3R1YWwsIHByZWRpY3RlZCkvbWVhbihhY3R1YWwpKjEwMCwgMSkNCiAgTTJbNSwgaV0gPSByb3VuZChybXNlKGFjdHVhbCwgcHJlZGljdGVkKSwgMikNCiAgTTNbNSwgaV0gPSByb3VuZChSRUckYWRqLnIuc3F1YXJlZCwgMikNCiAgTTRbNSwgaV0gPSByb3VuZChSRUckY29lZmZpY2llbnRzWzEsMV0sIDIpDQogIA0KICBvdXRCQ1tbaV1dID0gYmlhcyANCiAgb3V0TFJbW2ldXSA9IExSIA0KICBvdXRRTVtbaV1dID0gUU0NCiAgb3V0U0RbW2ldXSA9IFNEDQogIA0KfQ0KDQpjb2xuYW1lcyhNMSkgPC0gY29sbmFtZXMoTTIpIDwtIGMoInRtaW4iLCAidG1heCIsICJzcmFkIikNCmNvbG5hbWVzKE00KSA8LSBjb2xuYW1lcyhNMykgPC0gYygidG1pbiIsICJ0bWF4IiwgInNyYWQiKQ0KDQpyb3duYW1lcyhNMSkgPC0gcm93bmFtZXMoTTIpIDwtIGMoIk5DIiwgIkJDIiwgIkxSIiwgIlFNIiwgIlNEIikNCnJvd25hbWVzKE0zKSA8LSByb3duYW1lcyhNNCkgPC0gYygiTkMiLCAiQkMiLCAiTFIiLCAiUU0iLCAiU0QiKQ0KDQpuYW1lcyhvdXRCQykgPC0gbmFtZXMob3V0TFIpIDwtIGMoInRtaW4iLCAidG1heCIsICJzcmFkIikNCm5hbWVzKG91dFFNKSA8LSBuYW1lcyhvdXRTRCkgPC0gYygidG1pbiIsICJ0bWF4IiwgInNyYWQiKQ0KDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgUExPVFMNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgR2VuZXJhbCBwbG90IHNldHRpbmdzDQpwYXIob21hICAgID0gYyg0LjUsIDQuNSwgMC41LCAzKSwgICMgZ2VuZXJhbCBtYXJnaW5zDQogICAgbWZyb3cgID0gYyg0LCAzKSwgICAgICAgICAgICAgICAgIyBudW1iZXIgb2Ygc3ViLWZpZ3VyZXMNCiAgICBtYXIgICAgPSBjKDQuNSwyLjUsMS41LDEuNSksICAgICAgICAgICMgbWFyZ2lucyBwZXIgc3ViLWZpZ3VyZQ0KICAgIGZhbWlseSA9ICJzZXJpZiIsICAgICAgICAgICAgICAgICMgdGV4dCBmYW1pbHkNCiAgICBsd2QgICAgPSAxLjAsICAgICAgICAgICAgICAgICAgICAjIGxpbmUgd2lkdGgNCiAgICBsYXMgICAgPSAxLCAgICAgICAgICAgICAgICAgICAgICAjIHN0eWxlIG9mIGF4aXMgbGFiZWxzICANCiAgICBwY2ggICAgPSAxOSwgICAgICAgICAgICAgICAgICAgICAjIHBsb3R0aW5nIHBvaW50cw0KICAgIGNleCAgICA9IDAuNSwNCiAgICBwdHkgPSAicyINCikNCg0KIyBQTE9UUyBGT1IgU0lNUExFIEJJQVMgQ09SUkVDVElPTg0KdG1pbkMgPSB3ZFMkdG1pbiArIG91dEJDJHRtaW4NCnBsb3Qod2RTJHRtaW4sIHdkTyR0bWluLCB4bGltID0gYygwLDE0KSwgeWxpbSA9IGMoMCwxNCksIHhsYWIgPSAiTkFTQTogdG1pbiAoQykiLCB5bGFiID0gIk9CUzogdG1pbiAoQykiLCBjb2wgPSAiYmx1ZSIpDQpwb2ludHModG1pbkMsIHdkTyR0bWluLCBjb2wgPSAicmVkIikNCmFibGluZShjKDAsMSksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDEuNSkNCg0KdG1heEMgPSB3ZFMkdG1heCArIG91dEJDJHRtYXgNCnBsb3Qod2RTJHRtYXgsIHdkTyR0bWF4LCB4bGltID0gYyg4LDI4KSwgeWxpbSA9IGMoOCwyOCksIHhsYWIgPSAiTkFTQTogdG1heCAoQykiLCB5bGFiID0gIk9CUzogdG1heCAoQykiLCBjb2wgPSAiYmx1ZSIpDQpwb2ludHModG1heEMsIHdkTyR0bWF4LCBjb2wgPSAicmVkIikNCmFibGluZShjKDAsMSksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDEuNSkNCnRpdGxlKCJCaWFzcyBDb3JyZWN0aW9uIikNCg0Kc3JhZEMgPSB3ZFMkc3JhZCArIG91dEJDJHNyYWQNCnBsb3Qod2RTJHNyYWQsIHdkTyRzcmFkLCB4bGltID0gYygzLDMxKSwgeWxpbSA9IGMoMywzMSksIHhsYWIgPSAiTkFTQTogc3JhZCAoTUovbTIvZGF5KSIsIHlsYWIgPSAiT0JTOiBzcmFkIChNSi9tMi9kYXkpIiwgY29sID0gImJsdWUiKQ0KcG9pbnRzKHNyYWRDLCB3ZE8kc3JhZCwgY29sID0gInJlZCIpDQphYmxpbmUoYygwLDEpLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAxLjUpDQoNCg0KIyBQTE9UUyBGT1IgTElORUFSIFJFR1JFU1NJT04NCnRtaW5DID0gcHJlZGljdChvdXRMUiR0bWluLCBuZXdkYXRhID0gZGF0YS5mcmFtZShzaW1UID0gd2RTJHRtaW4pKQ0KcGxvdCh3ZFMkdG1pbiwgd2RPJHRtaW4sIHhsaW0gPSBjKDAsMTQpLCB5bGltID0gYygwLDE0KSwgeGxhYiA9ICJOQVNBOiB0bWluIChDKSIsIHlsYWIgPSAiT0JTOiB0bWluIChDKSIsIGNvbCA9ICJibHVlIikNCnBvaW50cyh0bWluQywgd2RPJHRtaW4sIGNvbCA9ICJyZWQiKQ0KYWJsaW5lKGMoMCwxKSwgY29sID0gImJsYWNrIiwgbHdkID0gMS41KQ0KDQp0bWF4QyA9IHByZWRpY3Qob3V0TFIkdG1heCwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoc2ltVCA9IHdkUyR0bWF4KSkNCnBsb3Qod2RTJHRtYXgsIHdkTyR0bWF4LCB4bGltID0gYyg4LDI4KSwgeWxpbSA9IGMoOCwyOCksIHhsYWIgPSAiTkFTQTogdG1heCAoQykiLCB5bGFiID0gIk9CUzogdG1heCAoQykiLCBjb2wgPSAiYmx1ZSIpDQpwb2ludHModG1heEMsIHdkTyR0bWF4LCBjb2wgPSAicmVkIikNCmFibGluZShjKDAsMSksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDEuNSkNCnRpdGxlKCJMaW5lYXIgUmVncmVzc2lvbiIpDQoNCnNyYWRDID0gcHJlZGljdChvdXRMUiRzcmFkLCBuZXdkYXRhID0gZGF0YS5mcmFtZShzaW1UID0gd2RTJHNyYWQpKQ0KcGxvdCh3ZFMkc3JhZCwgd2RPJHNyYWQsIHhsaW0gPSBjKDMsMzEpLCB5bGltID0gYygzLDMxKSwgeGxhYiA9ICJOQVNBOiBzcmFkIChNSi9tMi9kYXkpIiwgeWxhYiA9ICJPQlM6IHNyYWQgKE1KL20yL2RheSkiLCBjb2wgPSAiYmx1ZSIpDQpwb2ludHMoc3JhZEMsIHdkTyRzcmFkLCBjb2wgPSAicmVkIikNCmFibGluZShjKDAsMSksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDEuNSkNCg0KDQojIFBMT1RTIEZPUiBRVUFOVElMRSBNQVRDSElORw0KdG1pbkMgPSBwcmVkaWN0KG91dFFNJHRtaW4sIG5ld2RhdGEgPSBkYXRhLmZyYW1lKHNDREYgPSB3ZFMkdG1pbikpDQpwbG90KHdkUyR0bWluLCB3ZE8kdG1pbiwgeGxpbSA9IGMoMCwxNCksIHlsaW0gPSBjKDAsMTQpLCB4bGFiID0gIk5BU0E6IHRtaW4gKEMpIiwgeWxhYiA9ICJPQlM6IHRtaW4gKEMpIiwgY29sID0gImJsdWUiKQ0KcG9pbnRzKHRtaW5DLCB3ZE8kdG1pbiwgY29sID0gInJlZCIpDQphYmxpbmUoYygwLDEpLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAxLjUpDQoNCnRtYXhDID0gcHJlZGljdChvdXRRTSR0bWF4LCBuZXdkYXRhID0gZGF0YS5mcmFtZShzQ0RGID0gd2RTJHRtYXgpKQ0KcGxvdCh3ZFMkdG1heCwgd2RPJHRtYXgsIHhsaW0gPSBjKDgsMjgpLCB5bGltID0gYyg4LDI4KSwgeGxhYiA9ICJOQVNBOiB0bWF4IChDKSIsIHlsYWIgPSAiT0JTOiB0bWF4IChDKSIsIGNvbCA9ICJibHVlIikNCnBvaW50cyh0bWF4Qywgd2RPJHRtYXgsIGNvbCA9ICJyZWQiKQ0KYWJsaW5lKGMoMCwxKSwgY29sID0gImJsYWNrIiwgbHdkID0gMS41KQ0KdGl0bGUoIlF1YW50aWxlIE1hdGNoaW5nIikNCg0Kc3JhZEMgPSBwcmVkaWN0KG91dFFNJHNyYWQsIG5ld2RhdGEgPSBkYXRhLmZyYW1lKHNDREYgPSB3ZFMkc3JhZCkpDQpwbG90KHdkUyRzcmFkLCB3ZE8kc3JhZCwgeGxpbSA9IGMoMywzMSksIHlsaW0gPSBjKDMsMzEpLCB4bGFiID0gIk5BU0E6IHNyYWQgKE1KL20yL2RheSkiLCB5bGFiID0gIk9CUzogc3JhZCAoTUovbTIvZGF5KSIsIGNvbCA9ICJibHVlIikNCnBvaW50cyhzcmFkQywgd2RPJHNyYWQsIGNvbCA9ICJyZWQiKQ0KYWJsaW5lKGMoMCwxKSwgY29sID0gImJsYWNrIiwgbHdkID0gMS41KQ0KDQoNCiMgUExPVCBGT1IgU1RBVElTVElDQUwgRElTVFJJQlVUSU9OIFVTSU5HIFNQTElORVMNCnRtaW5DID0gcHJlZGljdChvdXRTRCR0bWluLCB3ZFMkdG1pbikkeQ0KcGxvdCh3ZFMkdG1pbiwgd2RPJHRtaW4sIHhsaW0gPSBjKDAsMTQpLCB5bGltID0gYygwLDE0KSwgeGxhYiA9ICJOQVNBOiB0bWluIChDKSIsIHlsYWIgPSAiT0JTOiB0bWluIChDKSIsIGNvbCA9ICJibHVlIikNCnBvaW50cyh0bWluQywgd2RPJHRtaW4sIGNvbCA9ICJyZWQiKQ0KYWJsaW5lKGMoMCwxKSwgY29sID0gImJsYWNrIiwgbHdkID0gMS41KQ0KDQp0bWF4QyA9IHByZWRpY3Qob3V0U0QkdG1heCwgd2RTJHRtYXgpJHkNCnBsb3Qod2RTJHRtYXgsIHdkTyR0bWF4LCB4bGltID0gYyg4LDI4KSwgeWxpbSA9IGMoOCwyOCksIHhsYWIgPSAiTkFTQTogdG1heCAoQykiLCB5bGFiID0gIk9CUzogdG1heCAoQykiLCBjb2wgPSAiYmx1ZSIpDQpwb2ludHModG1heEMsIHdkTyR0bWF4LCBjb2wgPSAicmVkIikNCmFibGluZShjKDAsMSksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDEuNSkNCnRpdGxlKCJTdGF0aXN0aWNhbCBEaXN0cmlidXRpb24iKQ0KDQpzcmFkQyA9IHByZWRpY3Qob3V0U0Qkc3JhZCwgd2RTJHNyYWQpJHkNCnBsb3Qod2RTJHNyYWQsIHdkTyRzcmFkLCB4bGltID0gYygzLDMxKSwgeWxpbSA9IGMoMywzMSksIHhsYWIgPSAiTkFTQTogc3JhZCAoTUovbTIvZGF5KSIsIHlsYWIgPSAiT0JTOiBzcmFkIChNSi9tMi9kYXkpIiwgY29sID0gImJsdWUiKQ0KcG9pbnRzKHNyYWRDLCB3ZE8kc3JhZCwgY29sID0gInJlZCIpDQphYmxpbmUoYygwLDEpLCBjb2wgPSAiYmxhY2siLCBsd2QgPSAxLjUpDQoNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBGSU5BTCBXRUFUSEVSIERBVEEgRk9SIE1PREVMSU5HDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQp3byA8LSB3ZA0Kd2MgPC0gZGF0YS5mcmFtZShkYXRlID0gd2QkZGF0ZSkNCg0KIyBBcHBseSB0aGUgcXVhbnRpbGUgbWF0Y2hpbmcgdG8gZGF0YXNldA0Kd2MkdG1pbiA8LSBwcmVkaWN0KG91dFFNJHRtaW4sIG5ld2RhdGEgPSBkYXRhLmZyYW1lKHNDREYgPSB3byR0bWluKSkNCndjJHRtYXggPC0gcHJlZGljdChvdXRRTSR0bWF4LCBuZXdkYXRhID0gZGF0YS5mcmFtZShzQ0RGID0gd28kdG1heCkpDQp3YyRzcmFkIDwtIHByZWRpY3Qob3V0UU0kc3JhZCwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoc0NERiA9IHdvJHNyYWQpKQ0KDQojIEZpbmFsIHdlYXRoZXIgZGF0YQ0KV0QgPC0gd2MNCg0KYGBgDQoNCg0KIyMgU09MQU5VTSBtb2RlbCBjYWxpYnJhdGlvbg0KDQpUaGUgU09MQU5VTSBtb2RlbCB3YXMgY2FsaWJyYXRlZCB1c2luZyB0ZW1wb3JhbCBkYXRhIG9uIGNhbm9weSBjb3ZlciBhbmQgYmlvbWFzcy4gQ2Fub3B5IGNvdmVyIGRhdGEgd2FzIGZpdHRlZCB0byBhIGJldGEgZnVuY3Rpb24sIHdoaWxlIGJpb21hc3MgZGF0YSB3YXMgZml0dGVkIHRvIGEgR29tcGVydHogZnVuY3Rpb24uIE5vbmxpbmVhciByZWdyZXNzaW9uIHdhcyBhcHBsaWVkIGZvciB0aGlzIGNhbGlicmF0aW9uLiANCg0KQ2xpY2sgb24gYGNvZGVgIHRvIHZpZXcgaG93IHRoZSBjYW5vcHkgY292ZXIgZGF0YSB3YXMgZml0dGVkIHRvIHRoZSBCZXRhIGN1cnZlIHVzaW5nIHRoZSBgRml0Q3VydmVTTWAgZnVuY3Rpb24gaW4gUi4NCg0KYGBge3IgY2xhc3Muc291cmNlPSdmb2xkLWhpZGUnLCByZXN1bHRzPSdob2xkJ30NCiMgbG9hZCB0aGVybWFsIHRpbWUgZnVuY3Rpb24NCnNvdXJjZSgiLi4vUi90aGVybWFsVGltZS5SIikNCnNvdXJjZSgiLi4vUi9Tb2xhbnVtTW9kZWwuUiIpDQpzb3VyY2UoIi4uL1IvRml0Q3VydmVTTS5SIikNCg0KIyBFbWVyZ2VuY3kgZGF5DQplZSA8LSBkYXRhLmZyYW1lKEVEYXk9YygxNiwgMzMsIDM0LCAyNCwgNDIpLA0KICAgICAgICAgICAgICAgICBDT0RFPWMoIkFNQSIsICJCUkUiLCAiSFVFIiwgIlBPRCIsICJZVU4iKSkNCkVEYXkgPC0gZWUkRURheQ0KbmFtZXMoRURheSkgPC0gYygiQU1BIiwgIkJSRSIsICJIVUUiLCAiUE9EIiwgIllVTiIpDQoNCiMgUmVhZCB3ZWF0aGVyIGRhdGENCndkIDwtIHJlYWQuY3N2KCJodHRwczovL2dpdGh1Yi5jb20vam5pbmFueWEvUG90YXRvX1lpZWxkX0dhcC9yYXcvcmVmcy9oZWFkcy9tYWluL0RhdGEvZGF0YXNldF9mb3JfbW9kZWxfY2FsaWJyYXRpb24uY3N2IikNCmNvbG5hbWVzKHdkKSA8LSB0b2xvd2VyKGNvbG5hbWVzKHdkKSkNCg0KIyBUaGVybWFsIHRpbWUgY29tcHV0YXRpb24NClRUIDwtIG1hdHJpeChucm93ID0gbGVuZ3RoKHdkJGRhdGUpLCBuY29sID0gNSkNCg0KZm9yKGkgaW4gMTo1KXsNCiAgdHQgPSB0aGVybWFsVGltZShkYXRlID0gd2QkZGF0ZSwgdG1pbiA9IHdkJHRtaW4sIHRtYXggPSB3ZCR0bWF4LA0KICAgICAgICAgICAgICAgICAgIHNvd2luZyA9ICIyMDIzLTEwLTI0IiwgZW5kSGFydmVzdCA9ICIyMDI0LTA0LTE4IiwNCiAgICAgICAgICAgICAgICAgICBFbWVyZ2VuY3lEYXlzID0gRURheVtpXSkNCiAgVFRbLGldID0gcm91bmQodHQkdHQsMSkNCn0NCg0KY29sbmFtZXMoVFQpIDwtIG5hbWVzKEVEYXkpDQpyb3duYW1lcyhUVCkgPC0gMDoobGVuZ3RoKHdkJGRhdGUpLTEpDQojaGVhZChUVCkNCg0KVFQgPC0gZGF0YS5mcmFtZShkYXRlID0gd2QkZGF0ZSwgZGFwID0gMDoobGVuZ3RoKHdkJGRhdGUpLTEpLCBUVCkNCg0KIyBUVCAgcGVyIHZhcmlldHkNCm91dENEIDwtIGFzLmRhdGEuZnJhbWUob3V0Q0QpDQpUVF9DRCA8LSBUVFtUVCRkYXAgJWluJSBvdXRDRCREQVAsIDI6N10NCg0KIyMjIGZ1bmN0aW9uIHRvIGNhbGlicmF0ZSB0aGUgbW9kZWwNCnRtIDwtIHZlY3RvcigpDQp0ZSA8LSB2ZWN0b3IoKQ0Kd21heCA8LSB2ZWN0b3IoKQ0KY2MgPC0gbGlzdCgpDQoNCmZvcihpIGluIDE6NSl7DQogIHggPC0gVFRfQ0RbLCAxK2ldDQogIHkgPC0gb3V0Q0RbLCAxK2ldDQogIGZpdHQuY2MgPC0gRml0Q3VydmVTTSh4LCB5LCB4ZnVuID0gIkJldGEiLCB4dGltZSA9ICJ0dCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgaW5pdC5wYXIgPSBjKDEwMCwgNTAwLCAwLjkpICwgdXNlLnBhci5kZWZhdWx0ID0gRkFMU0UpDQogIA0KICB0bVtpXSA8LSBmaXR0LmNjJHBhcmFtZXRlcnNbMV0NCiAgdGVbaV0gPC0gZml0dC5jYyRwYXJhbWV0ZXJzWzJdDQogIHdtYXhbaV0gPC0gZml0dC5jYyRwYXJhbWV0ZXJzWzNdDQogIA0KICBjY1tbaV1dIDwtIGZpdHQuY2MNCn0NCg0KIyBDcm9wIHBhcmFtZXRlcnMgZm9yIHRoZSBCZXRhIGZ1bmN0aW9uDQpuYW1lcyh0bSkgPC0gbmFtZXModGUpIDwtIG5hbWVzKHdtYXgpIDwtIGMoIkFNQSIsICJCUkUiLCAiSFVFIiwgIlBPRCIsICJZVU4iKQ0KbmFtZXMoY2MpIDwtIGMoIkFNQSIsICJCUkUiLCAiSFVFIiwgIlBPRCIsICJZVU4iKQ0KDQojIyMjIyMjIyMjIyMzDQojIyMjIyMjIyMjIyMjDQojIyMjIyMjIyMjIyMNCg0KcGFyKG1mcm93ID0gYygyLDMpLA0KICAgIG1hciA9IGMoMi41LDMuNSwyLjUsMC41KSwNCiAgICBsYXMgPSAxLCBwdHkgPSAicyIsIGNleCA9IDEuKQ0KIyBQTE9UUyBDQyBBTUFSSUxJUw0KcGxvdChjYyRBTUEkc2ltdWxhdGVkLmRhdGEkdGltZSwgY2MkQU1BJHNpbXVsYXRlZC5kYXRhJHNpbXVsYXRlZF9kYXRhLA0KICAgICB4bGFiID0gInRoZXJtYWwgdGltZSAoQypkYXkpIiwgeWxhYiA9ICJjYW5vcHkgY292ZXIgKCUpIiwgbGFzID0gMSwgeWxpbSA9IGMoMCwxKSwNCiAgICAgdHlwZSA9ICJsIiwgbHdkID0gMS41LCBtYWluID0gIkFtYXJpbGlzIiwgeGxpbSA9IGMoMCwxNDAwKSkNCnBvaW50cyhjYyRBTUEkZml0dGVkLmRhdGEkdGltZSwgY2MkQU1BJGZpdHRlZC5kYXRhJG9icy8xMDAsIGNvbCA9ICJyZWQiLCBsd2QgPSAxLjIsIGNleCA9IDEuNSkNCg0KIyBQTE9UUyBDQyBCUkVUQU5BDQpwbG90KGNjJEJSRSRzaW11bGF0ZWQuZGF0YSR0aW1lLCBjYyRCUkUkc2ltdWxhdGVkLmRhdGEkc2ltdWxhdGVkX2RhdGEsDQogICAgIHhsYWIgPSAidGhlcm1hbCB0aW1lIChDKmRheSkiLCB5bGFiID0gImNhbm9weSBjb3ZlciAoJSkiLCBsYXMgPSAxLCB5bGltID0gYygwLDEpLA0KICAgICB0eXBlID0gImwiLCBsd2QgPSAxLjUsIG1haW4gPSAiQnJldGHDsWEiLCB4bGltID0gYygwLDE0MDApKQ0KcG9pbnRzKGNjJEJSRSRmaXR0ZWQuZGF0YSR0aW1lLCBjYyRCUkUkZml0dGVkLmRhdGEkb2JzLzEwMCwgY29sID0gInJlZCIsIGx3ZCA9IDEuMiwgY2V4ID0gMS41KQ0KDQojIFBMT1RTIENDIEhVRVZPIERFIElORElPDQpwbG90KGNjJEhVRSRzaW11bGF0ZWQuZGF0YSR0aW1lLCBjYyRIVUUkc2ltdWxhdGVkLmRhdGEkc2ltdWxhdGVkX2RhdGEsDQogICAgIHhsYWIgPSAidGhlcm1hbCB0aW1lIChDKmRheSkiLCB5bGFiID0gImNhbm9weSBjb3ZlciAoJSkiLCBsYXMgPSAxLCB5bGltID0gYygwLDEpLA0KICAgICB0eXBlID0gImwiLCBsd2QgPSAxLjUsIG1haW4gPSAiSHVldm8gZGUgSW5kaW8iLCB4bGltID0gYygwLDE0MDApKQ0KcG9pbnRzKGNjJEhVRSRmaXR0ZWQuZGF0YSR0aW1lLCBjYyRIVUUkZml0dGVkLmRhdGEkb2JzLzEwMCwgY29sID0gInJlZCIsIGx3ZCA9IDEuMiwgY2V4ID0gMS41KQ0KDQojIFBMT1RTIENDIFBPREVST1NBDQpwbG90KGNjJFBPRCRzaW11bGF0ZWQuZGF0YSR0aW1lLCBjYyRQT0Qkc2ltdWxhdGVkLmRhdGEkc2ltdWxhdGVkX2RhdGEsDQogICAgIHhsYWIgPSAidGhlcm1hbCB0aW1lIChDKmRheSkiLCB5bGFiID0gImNhbm9weSBjb3ZlciAoJSkiLCBsYXMgPSAxLCB5bGltID0gYygwLDEpLA0KICAgICB0eXBlID0gImwiLCBsd2QgPSAxLjUsIG1haW4gPSAiUG9kZXJvc2EiLCB4bGltID0gYygwLDE0MDApKQ0KcG9pbnRzKGNjJFBPRCRmaXR0ZWQuZGF0YSR0aW1lLCBjYyRQT0QkZml0dGVkLmRhdGEkb2JzLzEwMCwgY29sID0gInJlZCIsIGx3ZCA9IDEuMiwgY2V4ID0gMS41KQ0KDQojIFBMT1RTIENDIFlVTkdBWQ0KcGxvdChjYyRZVU4kc2ltdWxhdGVkLmRhdGEkdGltZSwgY2MkWVVOJHNpbXVsYXRlZC5kYXRhJHNpbXVsYXRlZF9kYXRhLA0KICAgICB4bGFiID0gInRoZXJtYWwgdGltZSAoQypkYXkpIiwgeWxhYiA9ICJjYW5vcHkgY292ZXIgKCUpIiwgbGFzID0gMSwgeWxpbSA9IGMoMCwxKSwNCiAgICAgdHlwZSA9ICJsIiwgbHdkID0gMS41LCBtYWluID0gIll1bmdheSIsIHhsaW0gPSBjKDAsMTQwMCkpDQpwb2ludHMoY2MkWVVOJGZpdHRlZC5kYXRhJHRpbWUsIGNjJFlVTiRmaXR0ZWQuZGF0YSRvYnMvMTAwLCBjb2wgPSAicmVkIiwgbHdkID0gMS4yLCBjZXggPSAxLjUpDQoNCmBgYA0KDQpDbGljayBvbiBgY29kZWAgdG8gdmlldyBob3cgdGhlIGhhcnZlc3QgaW5kZXggKHR1YmVyL3RvdGFsIGJpb21hc3MpIGRhdGEgd2FzIGZpdHRlZCB0byB0aGUgR29tcGVydHogY3VydmUgdXNpbmcgdGhlIGBGaXRDdXJ2ZVNNYCBmdW5jdGlvbiBpbiBSLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2U9J2ZvbGQtaGlkZScsIHJlc3VsdHM9J2hvbGQnfQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBCSU9NQVNTIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMjIGRhdGVzIA0Kb3V0QkQgPC0gYXMuZGF0YS5mcmFtZShvdXRCRCkNCm91dEJEJERBUFs2XSA8LSAxNzcNCnplcm9zX3JvdyA8LSByZXAoMCwgNikNCmxhc3Rfcm93IDwtIGMoMTg1LCBhcHBseShvdXRCRFssMjo2XSwgMiwgbWF4LCBuYS5ybT1UUlVFKSkNCm91dEJEX25ldyA8LSByYmluZCh6ZXJvc19yb3csIG91dEJEKQ0Kb3V0QkRfbmV3IDwtIHJiaW5kKG91dEJEX25ldywgbGFzdF9yb3cpDQojb3V0QkRfbmV3JEFNQVs3XSA8LSBvdXRCRF9uZXckQU1BWzhdDQojb3V0QkRfbmV3JEFNQVs4XSA8LSBOQQ0KDQpUVF9CRCA8LSBUVFtUVCRkYXAgJWluJSBvdXRCRCREQVAsIDI6N10NCnplcm9zX3JvdyA8LSByZXAoMCwgNikNCmxhc3Rfcm93IDwtIGMoMTg1LCB1bmxpc3QoVFRfQkRbNiwyOjZdKSArIDE1MCkNClRUX0JEX25ldyA8LSByYmluZCh6ZXJvc19yb3csIFRUX0JEKQ0KVFRfQkRfbmV3IDwtIHJiaW5kKFRUX0JEX25ldywgbGFzdF9yb3cpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KYiA8LSB2ZWN0b3IoKQ0KdHUgPC0gdmVjdG9yKCkNCkEgPC0gdmVjdG9yKCkNCmhoIDwtIGxpc3QoKQ0KDQpmb3IoaSBpbiAxOjUpew0KICB4IDwtIFRUX0JEWywgMStpXQ0KICB5IDwtIG91dEJEWywgMStpXQ0KICANCiAgZml0dC5oaCA8LSBGaXRDdXJ2ZVNNKHgsIHksIHhmdW4gPSAiR29tcGVydHoiLCB4dGltZSA9ICJ0dCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgaW5pdC5wYXIgPSBjKDI1MCwgNjAwLCAwLjkpICwgdXNlLnBhci5kZWZhdWx0ID0gRkFMU0UpDQogIA0KICBiW2ldIDwtIGZpdHQuaGgkcGFyYW1ldGVyc1sxXQ0KICB0dVtpXSA8LSBmaXR0LmhoJHBhcmFtZXRlcnNbMl0NCiAgQVtpXSA8LSBmaXR0LmhoJHBhcmFtZXRlcnNbM10NCiAgDQogIGhoW1tpXV0gPC0gZml0dC5oaA0KfQ0KDQpuYW1lcyhiKSA8LSBuYW1lcyh0dSkgPC0gbmFtZXMoQSkgPC0gYygiQU1BIiwgIkJSRSIsICJIVUUiLCAiUE9EIiwgIllVTiIpDQpuYW1lcyhoaCkgPC0gYygiQU1BIiwgIkJSRSIsICJIVUUiLCAiUE9EIiwgIllVTiIpDQoNCg0KIyMjIyMjIyMjIyMjMw0KIyMjIyMjIyMjIyMjIw0KIyMjIyMjIyMjIyMjDQoNCnBhcihtZnJvdyA9IGMoMiwzKSwNCiAgICBtYXIgPSBjKDIuNSwzLjUsMi41LDAuNSksDQogICAgbGFzID0gMSwgcHR5ID0gInMiLCBjZXggPSAxLikNCiMgUExPVFMgSEkgQU1BUklMSVMNCnBsb3QoaGgkQU1BJHNpbXVsYXRlZC5kYXRhJHRpbWUsIGhoJEFNQSRzaW11bGF0ZWQuZGF0YSRzaW11bGF0ZWRfZGF0YSwNCiAgICAgeGxhYiA9ICJ0aGVybWFsIHRpbWUgKEMqZGF5KSIsIHlsYWIgPSAiaGFydmVzdCBpbmRleCAoJSkiLCBsYXMgPSAxLCB5bGltID0gYygwLDEpLA0KICAgICB0eXBlID0gImwiLCBsd2QgPSAxLjUsIG1haW4gPSAiQW1hcmlsaXMiLCB4bGltID0gYygwLDE3MDApKQ0KcG9pbnRzKGhoJEFNQSRmaXR0ZWQuZGF0YSR0aW1lLCBoaCRBTUEkZml0dGVkLmRhdGEkb2JzLCBjb2wgPSAicmVkIiwgbHdkID0gMS4yLCBjZXggPSAxLjUpDQoNCiMgUExPVFMgSEkgQlJFVEFOQQ0KcGxvdChoaCRCUkUkc2ltdWxhdGVkLmRhdGEkdGltZSwgaGgkQlJFJHNpbXVsYXRlZC5kYXRhJHNpbXVsYXRlZF9kYXRhLA0KICAgICB4bGFiID0gInRoZXJtYWwgdGltZSAoQypkYXkpIiwgeWxhYiA9ICJoYXJ2ZXN0IGluZGV4ICglKSIsIGxhcyA9IDEsIHlsaW0gPSBjKDAsMSksDQogICAgIHR5cGUgPSAibCIsIGx3ZCA9IDEuNSwgbWFpbiA9ICJCcmV0YcOxYSIsIHhsaW0gPSBjKDAsMTcwMCkpDQpwb2ludHMoaGgkQlJFJGZpdHRlZC5kYXRhJHRpbWUsIGhoJEJSRSRmaXR0ZWQuZGF0YSRvYnMsIGNvbCA9ICJyZWQiLCBsd2QgPSAxLjIsIGNleCA9IDEuNSkNCg0KIyBQTE9UUyBDQyBIVUVWTyBERSBJTkRJTw0KcGxvdChoaCRIVUUkc2ltdWxhdGVkLmRhdGEkdGltZSwgaGgkSFVFJHNpbXVsYXRlZC5kYXRhJHNpbXVsYXRlZF9kYXRhLA0KICAgICB4bGFiID0gInRoZXJtYWwgdGltZSAoQypkYXkpIiwgeWxhYiA9ICJoYXJ2ZXN0IGluZGV4ICglKSIsIGxhcyA9IDEsIHlsaW0gPSBjKDAsMSksDQogICAgIHR5cGUgPSAibCIsIGx3ZCA9IDEuNSwgbWFpbiA9ICJIdWV2byBkZSBJbmRpbyIsIHhsaW0gPSBjKDAsMTcwMCkpDQpwb2ludHMoaGgkSFVFJGZpdHRlZC5kYXRhJHRpbWUsIGhoJEhVRSRmaXR0ZWQuZGF0YSRvYnMsIGNvbCA9ICJyZWQiLCBsd2QgPSAxLjIsIGNleCA9IDEuNSkNCg0KIyBQTE9UUyBDQyBQT0RFUk9TQQ0KcGxvdChoaCRQT0Qkc2ltdWxhdGVkLmRhdGEkdGltZSwgaGgkUE9EJHNpbXVsYXRlZC5kYXRhJHNpbXVsYXRlZF9kYXRhLA0KICAgICB4bGFiID0gInRoZXJtYWwgdGltZSAoQypkYXkpIiwgeWxhYiA9ICJoYXJ2ZXN0IGluZGV4ICglKSIsIGxhcyA9IDEsIHlsaW0gPSBjKDAsMSksDQogICAgIHR5cGUgPSAibCIsIGx3ZCA9IDEuNSwgbWFpbiA9ICJQb2Rlcm9zYSIsIHhsaW0gPSBjKDAsMTcwMCkpDQpwb2ludHMoaGgkUE9EJGZpdHRlZC5kYXRhJHRpbWUsIGhoJFBPRCRmaXR0ZWQuZGF0YSRvYnMsIGNvbCA9ICJyZWQiLCBsd2QgPSAxLjIsIGNleCA9IDEuNSkNCg0KIyBQTE9UUyBDQyBZVU5HQVkNCnBsb3QoaGgkWVVOJHNpbXVsYXRlZC5kYXRhJHRpbWUsIGhoJFlVTiRzaW11bGF0ZWQuZGF0YSRzaW11bGF0ZWRfZGF0YSwNCiAgICAgeGxhYiA9ICJ0aGVybWFsIHRpbWUgKEMqZGF5KSIsIHlsYWIgPSAiaGFydmVzdCBpbmRleCAoJSkiLCBsYXMgPSAxLCB5bGltID0gYygwLDEpLA0KICAgICB0eXBlID0gImwiLCBsd2QgPSAxLjUsIG1haW4gPSAiWXVuZ2F5IiwgeGxpbSA9IGMoMCwxNzAwKSkNCnBvaW50cyhoaCRZVU4kZml0dGVkLmRhdGEkdGltZSwgaGgkWVVOJGZpdHRlZC5kYXRhJG9icywgY29sID0gInJlZCIsIGx3ZCA9IDEuMiwgY2V4ID0gMS41KQ0KDQoNCiMjIyMjIyMjIyMjIyMjIyMjIw0KDQp0bS5kYXAgPC0gdmVjdG9yKCkNCnRlLmRhcCA8LSB2ZWN0b3IoKQ0Kd21heC5kYXAgPC0gdmVjdG9yKCkNCg0KZm9yKGkgaW4gMTo1KXsNCiAgeCA8LSBUVF9DRCRkYXANCiAgeSA8LSBvdXRDRFssIDEraV0NCiAgZml0dC5jYyA8LSBGaXRDdXJ2ZVNNKHgsIHksIHhmdW4gPSAiQmV0YSIsIHh0aW1lID0gImRhcCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgaW5pdC5wYXIgPSBjKDQwLCAxMjAsIDAuOSkgLCB1c2UucGFyLmRlZmF1bHQgPSBGQUxTRSkNCiAgDQogIHRtLmRhcFtpXSA8LSBmaXR0LmNjJHBhcmFtZXRlcnNbMV0NCiAgdGUuZGFwW2ldIDwtIGZpdHQuY2MkcGFyYW1ldGVyc1syXQ0KICB3bWF4LmRhcFtpXSA8LSBmaXR0LmNjJHBhcmFtZXRlcnNbM10NCiAgDQp9DQoNCm5hbWVzKHRtLmRhcCkgPC0gbmFtZXModGUuZGFwKSA8LSBuYW1lcyh3bWF4LmRhcCkgPC0gYygiQU1BIiwgIkJSRSIsICJIVUUiLCAiUE9EIiwgIllVTiIpDQoNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgYmV0YSBmdW5jdGlvbg0KZl9iZXRhIDwtIGZ1bmN0aW9uKHQsIHRtLCB0ZSwgd21heCl7DQogIGNjPXdtYXgqKDErKHRlLXQpLyh0ZS10bSkpKigodC90ZSleKHRlLyh0ZS10bSkpKQ0KICBjYz1pZmVsc2UoY2M+MCwgY2MsIDApDQp9DQoNCiMgZ29tcGVydHogZnVuY3Rpb24NCmZfZ29tcGVydHogPC0gZnVuY3Rpb24odCwgYiwgdHUsIEEpew0KICBBKihleHAoLWV4cCgtKDEvYikqKHQtdHUpKSkpDQp9DQoNCg0KIyMjIENDIGRhaWx5IGJhc2lzDQp2YXIgPC0gYygiQU1BIiwgIkJSRSIsICJIVUUiLCAiUE9EIiwgIllVTiIpDQoNCndkJGRhcCA8LSAwOihsZW5ndGgod2QkZGF0ZSktMSkNCndkJGNjQU1BIDwtIGZfYmV0YSh3ZCRkYXAsIHRtLmRhcFsiQU1BIl0sIHRlLmRhcFsiQU1BIl0sIHdtYXguZGFwWyJBTUEiXSkNCndkJGNjQlJFIDwtIGZfYmV0YSh3ZCRkYXAsIHRtLmRhcFsiQlJFIl0sIHRlLmRhcFsiQlJFIl0sIHdtYXguZGFwWyJCUkUiXSkNCndkJGNjSFVFIDwtIGZfYmV0YSh3ZCRkYXAsIHRtLmRhcFsiSFVFIl0sIHRlLmRhcFsiSFVFIl0sIHdtYXguZGFwWyJIVUUiXSkNCndkJGNjUE9EIDwtIGZfYmV0YSh3ZCRkYXAsIHRtLmRhcFsiUE9EIl0sIHRlLmRhcFsiUE9EIl0sIHdtYXguZGFwWyJQT0QiXSkNCndkJGNjWVVOIDwtIGZfYmV0YSh3ZCRkYXAsIHRtLmRhcFsiWVVOIl0sIHRlLmRhcFsiWVVOIl0sIHdtYXguZGFwWyJZVU4iXSkNCg0Kd2QkcGFyIDwtIHdkJHNyYWQqMC40OA0Kd2QkaW50QU1BIDwtIHdkJHNyYWQqd2QkY2NBTUENCndkJGludEJSRSA8LSB3ZCRzcmFkKndkJGNjQlJFDQp3ZCRpbnRIVUUgPC0gd2Qkc3JhZCp3ZCRjY0hVRQ0Kd2QkaW50UE9EIDwtIHdkJHNyYWQqd2QkY2NQT0QNCndkJGludFlVTiA8LSB3ZCRzcmFkKndkJGNjWVVODQoNCndkJGN1bUFNQSA8LSBjdW1zdW0od2QkaW50QU1BKQ0Kd2QkY3VtQlJFIDwtIGN1bXN1bSh3ZCRpbnRCUkUpDQp3ZCRjdW1IVUUgPC0gY3Vtc3VtKHdkJGludEhVRSkNCndkJGN1bVBPRCA8LSBjdW1zdW0od2QkaW50UE9EKQ0Kd2QkY3VtWVVOIDwtIGN1bXN1bSh3ZCRpbnRZVU4pDQoNCkNVTSA8LSBkYXRhLmZyYW1lKEFNQSA9IHdkJGN1bUFNQVtUVF9CRCRkYXBdLA0KICAgICAgICAgICAgICAgICAgQlJFID0gd2QkY3VtQlJFW1RUX0JEJGRhcF0sDQogICAgICAgICAgICAgICAgICBIVUUgPSB3ZCRjdW1IVUVbVFRfQkQkZGFwXSwNCiAgICAgICAgICAgICAgICAgIFBPRCA9IHdkJGN1bVBPRFtUVF9CRCRkYXBdLA0KICAgICAgICAgICAgICAgICAgWVVOID0gd2QkY3VtWVVOW1RUX0JEJGRhcF0pDQoNCg0KUlVFIDwtIGMoc3VtbWFyeShsbShvdXRURE0kQU1BKjEwMCB+IENVTSRBTUEpKSRjb2VmZmljaWVudHNbMl0sDQogICAgICAgICBzdW1tYXJ5KGxtKG91dFRETSRCUkUqMTAwIH4gQ1VNJEJSRSkpJGNvZWZmaWNpZW50c1syXSwNCiAgICAgICAgIHN1bW1hcnkobG0ob3V0VERNJEhVRSoxMDAgfiBDVU0kSFVFKSkkY29lZmZpY2llbnRzWzJdLA0KICAgICAgICAgc3VtbWFyeShsbShvdXRURE0kUE9EKjEwMCB+IENVTSRQT0QpKSRjb2VmZmljaWVudHNbMl0sDQogICAgICAgICBzdW1tYXJ5KGxtKG91dFRETSRZVU4qMTAwIH4gQ1VNJFlVTikpJGNvZWZmaWNpZW50c1syXSkNCm5hbWVzKFJVRSkgPC0gdmFyDQoNCkRNQy5iY2sgPC0gb3V0RE1DIA0KRE1DID0gYXBwbHkoRE1DLmJja1ssMjo2XSwyLG1heCxuYS5ybT1UUlVFKQ0KDQpWQVIgPSBuYW1lcyhETUMpDQpwYXJhbXMgPC0gZGF0YS5mcmFtZShWQVIsIA0KICAgICAgICAgICAgICAgICAgICAgcm91bmQodGUsMSksIHJvdW5kKHRtLDEpLCByb3VuZCh3bWF4LDIpLCANCiAgICAgICAgICAgICAgICAgICAgIHJvdW5kKGIsMSksIHJvdW5kKHR1LDEpLCByb3VuZChBLDIpLA0KICAgICAgICAgICAgICAgICAgICAgcm91bmQoUlVFLDIpLCByb3VuZChETUMsMikpDQoNCmNvbG5hbWVzKHBhcmFtcyk8LSBjKCJDT0RFIiwidGUiLCJ0bSIsIndtYXgiLA0KICAgICAgICAgICAgICAgICAgICAgImIiLCJ0dSIsIkEiLCJSVUUiLCJETUMiKQ0Kcm93bmFtZXMocGFyYW1zKSA8LSAxOjUNCg0KYGBgDQoNClRoZSBjcm9wIHBhcmFtZXRlcnMgb2YgdGhlIFNPTEFOVU0gbW9kZWwgd2VyZSBkZXRlcm1pbmVkIGZvciBlYWNoIHZhcmlldHkuICANCg0KYGBge3IgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9DQp5MSA8LSBjKCJ0aGVybWFsIHRpbWUgYXQgdGhlIG1heGltdW0gZ3Jvd3RoIHJhdGUgKHRlKSIsInRoZXJtYWwgdGltZSBhdCB0aGUgbWF4aW11bSBjYW5vcHkgY292ZXIgKHRtKSIsIm1heGltdW0gY2Fub3B5IGNvdmVyICh3bWF4KSIsInRoZXJtYWwgdGltZSBhdCB0aGUgaW5pdGlhbCBzbG9wZSBvZiBwYXJ0aXRpb24gY3VydmUgKGIpIiwidGhlcm1hbCB0aW1lIGF0IHRoZSBtYXhpbXVtIGdyb3d0aCByYXRlIG9mIHBhcnRpdGlvbiBjdXJ2ZSAodHUpIiwibWF4aW11bSBoYXJ2ZXN0IGluZGV4IChBKSIsInJhZGlhdGlvbiB1c2UgZWZmaWNpZW5jeSAoUlVFKSIsImRyeSBtYXR0ZXIgY29uY2VudHJhdGlvbiBvZiB0dWJlcnMgKERNQykiKQ0KeTIgPC0gYygiOTczLjIiLCAiNDgxLjIiLCAiMC45NiIsICIyNzMuMiIsICI1NDcuNiIsICIwLjkwIiwgIjEuMjAiLCAiMC4xNyIpDQp5MyA8LSBjKCI5NDYuOCIsICIzMTQuNyIsICIwLjk1IiwgIjI1Ni43IiwgIjcwMC44IiwgIjAuNzYiLCAiMS4xMSIsICIwLjI0IikNCnk0IDwtIGMoIjkwNC45IiwgIjM3MS42IiwgIjAuNzkiLCAiMjY5LjciLCAiNjYyLjYiLCAiMC44OSIsICIxLjI4IiwgIjAuMjQiKQ0KeTUgPC0gYygiODk1LjEiLCAiMzUwLjEiLCAiMS4wMCIsICIyMDQuMCIsICI4MTYuNCIsICIwLjgwIiwgIjEuNjkiLCAiMC4yMyIpDQp5NiA8LSBjKCI3ODQuMCIsICIyMjIuNCIsICIwLjg4IiwgIjI5NC42IiwgIjYyOC4xIiwgIjAuOTAiLCAiMS44MiIsICIwLjE4IikNCg0KDQp0YiA8LSBkYXRhLmZyYW1lKHkxLCB5MiwgeTMsIHk0LCB5NSwgeTYpDQpjb2xuYW1lcyh0YikgPC0gYygiUEFSQU1FVEVSIiwgIkFNQVJJTElTIiwgIkJSRVRBTkEiLCAiSFVFVk8gREUgSU5ESU8iLCAiUE9ERVJPU0EiLCAiWVVOR0FZIikNCg0Ka25pdHI6OmthYmxlKHRiLCBjYXB0aW9uID0gIlRhYmxlIDEuIENyb3AgcGFyYW1ldGVycyBvZiB0aGUgU09MQU5VTSBtb2RlbCBmb3IgdGhlIDUgbW9zdCBjb21tb24gdmFyaWV0aWVzIHVzZWQgaW4gQ2h1Z2F5LCBMYSBMaWJlcnRhZCwgaW4gUGVydS4iKQ0KDQpgYGANCg0KDQojIyBEZXRlcm1pbmF0aW9uIG9mIG9wdGltdW0gcGxhbnRpbmcgZGF0ZQ0KDQpEZXRlcm1pbmF0aW9uIG9mIG9wdGltdW0gcGxhbnRpbmcgZGF0ZSBpbnZvbHZlcyBpZGVudGlmeWluZyB0aGUgYmVzdCB0aW1lIHRvIHBsYW50IGEgY3JvcCB0byBtYXhpbWl6ZSB5aWVsZCBhbmQgbWluaW1pemUgcmlza3MgZnJvbSBhZHZlcnNlIHdlYXRoZXIgY29uZGl0aW9ucywgcGVzdHMsIG9yIGRpc2Vhc2VzLiBUaGlzIHByb2Nlc3MgY29uc2lkZXJzIGZhY3RvcnMgc3VjaCBhcyB0ZW1wZXJhdHVyZSwgcmFpbmZhbGwsIGFuZCBkYXkgbGVuZ3RoIHRvIGVuc3VyZSBvcHRpbWFsIGdyb3d0aCBjb25kaXRpb25zLiBGb3IgdGhpcywgZGF0YSBmcm9tIHRoZSBJbnRlZ3JhdGVkIEFncmljdWx0dXJhbCBTdGF0aXN0aWNzIFN5c3RlbSB3YXMgdXNlZCB0byBzdXBwb3J0IHRoZSBhbmFseXNpcyBhbmQgaWRlbnRpZnkgdGhlIG1vc3Qgc3VpdGFibGUgcGxhbnRpbmcgZGF0ZXMgYmFzZWQgb24gaGlzdG9yaWNhbCBhZ3JpY3VsdHVyYWwgYW5kIGNsaW1hdGljIHRyZW5kcy4NCg0KYGBge3IgY2xhc3Muc291cmNlPSdmb2xkLWhpZGUnLCByZXN1bHRzPSdob2xkJ30NCnMxIDwtIHJlYWQuY3N2KCIuLi9EYXRhL291dF9uYXRpb25hbF9wb3RhdG9fZGF0YS5jc3YiKQ0KDQojIGRhdGEgZm9yIExhIExpYmVydGFkDQpMTCA8LSBzMVtzMSRERVBBUlRBTUVOVE8gPT0gIkxBIExJQkVSVEFEIiwgXQ0KI3N1bW1hcnkoTEwpDQpMTCRZWVlZIDwtIExMJEFOSU8NCkxMJE1NIDwtIExMJE1FUw0KDQojIGNoZWNrIENPU0VDSEE9PTAgJiBQUk9EVUNDSU9OPT0wDQojc3VtKExMJFBST0RVQ0NJT05bTEwkQ09TRUNIQSA9PSAwXSkNCiNzdW0oTEwkQ09TRUNIQVtMTCRQUk9EVUNUTyA9PSAwXSkNCg0KIyBtb250bHkgc3VtbWFyeSBmb3IgTEwNCnNtckxMLk0gPC0gTEwgJT4lDQogIGdyb3VwX2J5KFlZWVksTU0pICU+JQ0KICBzdW1tYXJpc2UoU0lFTUJSQSA9IHN1bShTSUVNQlJBKSwNCiAgICAgICAgICAgIENPU0VDSEEgPSBzdW0oQ09TRUNIQSksDQogICAgICAgICAgICBQUk9EVUNDSU9OID0gc3VtKFBST0RVQ0NJT04pKQ0KDQojIHllYXJseSBzdW1tYXJ5IGZvciBMTA0Kc21yTEwuWSA8LSBMTCAlPiUNCiAgZ3JvdXBfYnkoWVlZWSkgJT4lDQogIHN1bW1hcmlzZShTSUVNQlJBID0gc3VtKFNJRU1CUkEpLA0KICAgICAgICAgICAgQ09TRUNIQSA9IHN1bShDT1NFQ0hBKSwNCiAgICAgICAgICAgIFBST0RVQ0NJT04gPSBzdW0oUFJPRFVDQ0lPTikpDQoNCiMgeWllbGQgZXN0aW1hdGlvbg0Kc21yTEwuWSA8LSBhcy5kYXRhLmZyYW1lKHNtckxMLlkpDQpzbXJMTC5ZJFJFTkRJTUlFTlRPIDwtIHNtckxMLlkkUFJPRFVDQ0lPTi9zbXJMTC5ZJENPU0VDSEENCg0KIyBkYXRhIGZvciBDaHVnYXkNCkNIIDwtIExMW0xMJFBST1ZJTkNJQSA9PSAiU0FOQ0hFWiBDQVJSSU9OIiAmIExMJERJU1RSSVRPID09ICJDSFVHQVkiLCBdDQojc3VtbWFyeShDSCkNCg0KIyBtb250bHkgc3VtbWFyeSBmb3IgTEwNCnNtckNILk0gPC0gQ0ggJT4lDQogIGdyb3VwX2J5KFlZWVksTU0pICU+JQ0KICBzdW1tYXJpc2UoU0lFTUJSQSA9IHN1bShTSUVNQlJBKSwNCiAgICAgICAgICAgIENPU0VDSEEgPSBzdW0oQ09TRUNIQSksDQogICAgICAgICAgICBQUk9EVUNDSU9OID0gc3VtKFBST0RVQ0NJT04pKQ0KDQojIGRhdGEgZm9yIGZpZ3VyZQ0KbiA8LSBsZW5ndGgoc21yQ0guTSRZWVlZKQ0KWWVhciA8LSBjKHNtckNILk0kWVlZWSwgc21yQ0guTSRZWVlZKQ0KTW9udGggPC0gYyhzbXJDSC5NJE1NLCBzbXJDSC5NJE1NKQ0KQXJlYSA8LSBjKHNtckNILk0kU0lFTUJSQSwgc21yQ0guTSRDT1NFQ0hBKQ0KVHlwZSA8LSBjKHJlcCgiUGxhbnRlZCIsIG4pLCByZXAoIkhhcnZlc3RlZCIsIG4pKQ0KDQpkZiA8LSBkYXRhLmZyYW1lKFllYXIsIE1vbnRoLCBBcmVhLCBUeXBlKQ0KZGYkWWVhciA8LSBhcy5mYWN0b3IoWWVhcikNCg0KIyBtZWFuIHZhbHVlcw0KbWVhbl92YWx1ZXMgPC0gZGYgJT4lDQogIGdyb3VwX2J5KE1vbnRoLCBUeXBlKSAlPiUNCiAgc3VtbWFyaXplKG1lYW5fYXJlYSA9IG1lYW4oQXJlYSwgbmEucm0gPSBUUlVFKSkNCg0KIyBkZWZpbmUgZG91YmxlIGdhdXNzaWFuIGZ1bmN0aW9uDQpkb3VibGVfZ2F1c3NpYW4gPC0gZnVuY3Rpb24oeCwgYTEsIGIxLCBjMSwgYTIsIGIyLCBjMikgew0KICBhMSAqIGV4cCgtKHggLSBiMSleMiAvICgyICogYzFeMikpICsgYTIgKiBleHAoLSh4IC0gYjIpXjIgLyAoMiAqIGMyXjIpKQ0KfQ0KDQojIGZpdCBjdXJ2ZQ0KZml0X21vZGVscyA8LSBtZWFuX3ZhbHVlcyAlPiUNCiAgZ3JvdXBfYnkoVHlwZSkgJT4lDQogIGRvKGZpdCA9IG5sc0xNKG1lYW5fYXJlYSB+IGRvdWJsZV9nYXVzc2lhbihNb250aCwgYTEsIGIxLCBjMSwgYTIsIGIyLCBjMiksDQogICAgICAgICAgICAgICAgIGRhdGEgPSAuLCANCiAgICAgICAgICAgICAgICAgc3RhcnQgPSBsaXN0KGExID0gMTAsIGIxID0gNiwgYzEgPSAxLCBhMiA9IDEwLCBiMiA9IDEwLCBjMiA9IDEpKSkNCg0KIyBzYXZlIGNvZWZmaWNpZW50cyBvZiB0aGUgbW9kZWxzDQpmaXRfcGFyYW1zIDwtIGZpdF9tb2RlbHMgJT4lDQogIHJvd3dpc2UoKSAlPiUNCiAgbXV0YXRlKHBhcmFtcyA9IGxpc3QoY29lZihmaXQpKSkNCg0KIyBnYXVzc2lhbiBjdXJ2ZXMNCmdhdXNzaWFuX2N1cnZlcyA8LSBmaXRfcGFyYW1zICU+JQ0KICByb3d3aXNlKCkgJT4lDQogIGRvKGRhdGEuZnJhbWUoTW9udGggPSBzZXEobWluKG1lYW5fdmFsdWVzJE1vbnRoKSwgbWF4KG1lYW5fdmFsdWVzJE1vbnRoKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogICAgICAgICAgICAgICAgQXJlYSA9IGRvdWJsZV9nYXVzc2lhbihzZXEobWluKG1lYW5fdmFsdWVzJE1vbnRoKSwgbWF4KG1lYW5fdmFsdWVzJE1vbnRoKSwgbGVuZ3RoLm91dCA9IDEwMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJHBhcmFtc1tbMV1dLCAuJHBhcmFtc1tbMl1dLCAuJHBhcmFtc1tbM11dLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kcGFyYW1zW1s0XV0sIC4kcGFyYW1zW1s1XV0sIC4kcGFyYW1zW1s2XV0pLA0KICAgICAgICAgICAgICAgIFR5cGUgPSAuJFR5cGUpKQ0KDQoNCiMgcGNoDQpzaGFwZV92YWx1ZXMgPC0gYygwLCAxLCAyLCAzLCA0LCA1LCA2LCA3LCA4KQ0KDQojIGZpZ3VyZQ0KZ3AgPC0gZ2dwbG90KGRhdGEgPSBkZikgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gTW9udGgsIHkgPSBBcmVhLCBzaGFwZSA9IFllYXIpLCANCiAgICAgICAgICAgICBzaXplID0gMi41LCBjb2wgPSAiZ3JheTMwIikgKw0KICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gc2hhcGVfdmFsdWVzKSArDQogIGZhY2V0X3dyYXAofiBUeXBlKSArDQogIGxhYnModGl0bGUgPSAiRGV0ZXJtaW5pbmcgdGhlIG9wdGltdW0gcGxhbnRpbmcgZGF0ZSBmb3IgdGhlIGNyb3BwaW5nIHNlYXNvbiBpbiBDaHVnYXkiLA0KICAgICAgIHkgPSAiQXJlYSAoaGEpIikgKyANCiAgZ2VvbV9wb2ludChkYXRhID0gbWVhbl92YWx1ZXMsIGFlcyh4ID0gTW9udGgsIHkgPSBtZWFuX2FyZWEpLCANCiAgICAgICAgICAgICBjb2wgPSAicmVkIiwgc2l6ZSA9IDMpKw0KICBnZW9tX2xpbmUoZGF0YSA9IGdhdXNzaWFuX2N1cnZlcywgYWVzKHggPSBNb250aCwgeSA9IEFyZWEpLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpDQoNCmdwMiA9IGdwDQpwbG90KGdwMikNCg0KDQoNCiMjIyMjDQojIyMjIw0KDQojeCA8LSBzbXJDSC5NJE1NDQojeSA8LSBzbXJDSC5NJFNJRU1CUkENCiN4bSA8LSAxOjEyDQojeW0gPC0gbWVhbl92YWx1ZXMkbWVhbl9hcmVhW21lYW5fdmFsdWVzJFR5cGUgPT0gIlBsYW50ZWQiXQ0KIw0KI3BvaW50c0NvbG9ycyA8LSByZ2IoMCwgMCwgMC45OSwgYWxwaGEgPSAwLjMpDQojcGxvdCh4LCB5LCBheGVzID0gRkFMU0UsIHhsYWIgPSAiIiwgeWxhYiA9ICIiLCANCiMgICAgIHBjaCA9IDIwLCBjb2wgPSBwb2ludHNDb2xvcnMsIGNleCA9IDEuMikNCiNib3goKQ0KIw0KI3BvaW50cyh4bSwgeW0sIHBjaCA9IC0zMCwgY29sID0gInJlZCIsIGNleCA9IDEuMiwgbHdkID0gMS41KQ0KDQoNCmBgYA0KDQojIyBEZXRlcm1pbmF0aW9uIG9mIHBvdGVudGlhbCB5aWVsZHMNCg0KRm9sbG93aW5nIHRoZSBtZXRvZG9sb2d5IG9mIFNpbHZhIGV0IGFsLiBbKDIwMjIpXShodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmFnc3kuMjAyMi4xMDMzODMpLCB0aHJlZSB0eXBlcyBvZiBwb3RlbnRpYWwgeWllbGQgKFlwYSwgWXBiLCBhbmQgWXBjKSB3ZXJlIHVzZWQgdG8gZXZhbHVhdGUgYW5kIGNvbXBhcmUgY3JvcCB5aWVsZCBwb3RlbnRpYWwgdW5kZXIgZGlmZmVyZW50IHBsYW50aW5nIHNjZW5hcmlvcywgY29uc2lkZXJpbmcgdmFyaWF0aW9ucyBpbiBzb3dpbmcgZGF0ZXMgYW5kIGNyb3AgdmFyaWV0aWVzLg0KDQotICoqWXBhKiogcmVwcmVzZW50cyB0aGUgcG90ZW50aWFsIHlpZWxkIHNpbXVsYXRlZCBmb3IgdGhlIGhpZ2hlc3QteWllbGRpbmcgdmFyaWV0eSwgcGxhbnRlZCBvbiB0aGUgb3B0aW11bSBzb3dpbmcgZGF0ZSBmb3IgdGhlIGdyb3dpbmcgc2Vhc29uLiBUaGlzIHZhbHVlIHJlZmxlY3RzIHRoZSBtYXhpbXVtIGFjaGlldmFibGUgeWllbGQgZm9yIGEgc3BlY2lmaWMgc2l0ZSBpbiBhIGdpdmVuIHNlYXNvbiwgdXNpbmcgdGhlIGJlc3QgdmFyaWV0eSBhbmQgdGhlIG9wdGltYWwgcGxhbnRpbmcgZGF0ZS4gVGhlIG9wdGltdW0gc293aW5nIGRhdGUgaXMgaWRlbnRpZmllZCB3aXRoaW4gYSB0aHJlZS1tb250aCB3aW5kb3cgYXJvdW5kIHRoZSBtZWFuIG9ic2VydmVkIHBsYW50aW5nIGRhdGUgaW4gZmFybWVyIGZpZWxkIGRhdGEsIHNwZWNpZmljYWxseSB3aXRoaW4gwrEgNiB3ZWVrcyBmcm9tIHRoaXMgYXZlcmFnZSBkYXRlLg0KDQotICoqWXBiKiogYWxzbyByZXByZXNlbnRzIHNpbXVsYXRlZCB5aWVsZCBwb3RlbnRpYWwgZm9yIHRoZSBoaWdoZXN0LXlpZWxkaW5nIHZhcmlldHkgYnV0IGlzIGNhbGN1bGF0ZWQgdXNpbmcgdGhlIGFjdHVhbCBwbGFudGluZyBkYXRlcyBvYnNlcnZlZCBpbiBlYWNoIHNwZWNpZmljIGZpZWxkLiBZcGIgcHJvdmlkZXMgYW4gZXN0aW1hdGUgb2YgdGhlIHBvdGVudGlhbCB5aWVsZCBhdHRhaW5hYmxlIGluIGVhY2ggZmllbGQgd2l0aCB0aGUgaGlnaGVzdC15aWVsZGluZyB2YXJpZXR5IG9uIHRoZSByZWNvcmRlZCBwbGFudGluZyBkYXRlLg0KDQotICoqWXBjKiogc2ltdWxhdGVzIHRoZSB5aWVsZCBwb3RlbnRpYWwgYmFzZWQgb24gYm90aCB0aGUgYWN0dWFsIHZhcmlldHkgdXNlZCBieSB0aGUgZmFybWVyIGFuZCB0aGUgYWN0dWFsIHBsYW50aW5nIGRhdGUgb2JzZXJ2ZWQgaW4gZWFjaCBmaWVsZC4gVGhpcyBtZWFzdXJlIHJlZmxlY3RzIHlpZWxkIHBvdGVudGlhbCB1bmRlciB0aGUgc3BlY2lmaWMgY29uZGl0aW9ucyBjaG9zZW4gYnkgdGhlIGZhcm1lciwgaW5jbHVkaW5nIGJvdGggdGhlaXIgc2VsZWN0ZWQgdmFyaWV0eSBhbmQgcGxhbnRpbmcgZGF0ZS4gSW1wb3J0YW50bHksIFlwYyBkb2VzIG5vdCBhY2NvdW50IGZvciB0aGUgaW50ZXJhY3Rpb24gYmV0d2VlbiB2YXJpZXR5IGFuZCBzb3dpbmcgZGF0ZSwgd2hpY2ggY2FuIGltcGFjdCByZXNvdXJjZSB1c2UgZWZmaWNpZW5jeS4NCg0KSW4gc3VtbWFyeSwgKipZcGEqKiByZXByZXNlbnRzIHRoZSBpZGVhbCBtYXhpbXVtIHlpZWxkLCAqKllwYioqIGluZGljYXRlcyBwb3RlbnRpYWwgeWllbGQgdW5kZXIgcmVhbCBzb3dpbmcgZGF0ZXMgYnV0IHdpdGggdGhlIGJlc3QgdmFyaWV0eSwgYW5kICoqWXBjKiogc2hvd3MgdGhlIHlpZWxkIHBvdGVudGlhbCB1c2luZyB0aGUgYWN0dWFsIHZhcmlldHkgYW5kIHNvd2luZyBkYXRlIHNlbGVjdGVkIGJ5IGVhY2ggZmFybWVyLg0KDQoNCmBgYHtyIGNsYXNzLnNvdXJjZT0nZm9sZC1oaWRlJywgcmVzdWx0cz0naG9sZCd9DQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBNb2RlbGluZyBwb3RlbnRpYWwgeWllbGQNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmxvYWQoIkM6L1VzZXJzL2puaW5hbnlhL09uZURyaXZlIC0gQ0dJQVIvbm9uaS9HaXRodWIgcHJvamVjdHMvUG90YXRvX1lpZWxkX0dhcC9SL0Nyb3BQYXJhbXNMaXN0LlJkYXRhIikNCiMgY29uc2lkZXIgMTAgeWVhcnMNCm55ZWFycyA8LSAyMDEwOjIwMjINCg0KIyBFbWVyZ2VuY3kgZGF5DQplZSA8LSBkYXRhLmZyYW1lKEVEYXk9YygxNiwgMzMsIDM0LCAyNCwgNDIpLA0KICAgICAgICAgICAgICAgICBDT0RFPWMoIkFNQSIsICJCUkUiLCAiSFVFIiwgIlBPRCIsICJZVU4iKSkNCkVEYXkgPC0gZWUkRURheQ0KbmFtZXMoRURheSkgPC0gYygiQU1BIiwgIkJSRSIsICJIVUUiLCAiUE9EIiwgIllVTiIpDQoNCg0Kc3dnRGF0ZXMgPC0gYygiMjAyMC0wMy0wNSIsICIyMDIwLTAzLTEwIiwgIjIwMjAtMDMtMTUiLCAiMjAyMC0wMy0yMCIsICIyMDIwLTAzLTI1IiwgIjIwMjAtMDMtMzAiLA0KICAgICAgICAgICAgICAiMjAyMC0wNC0wNSIsICIyMDIwLTA0LTEwIiwgIjIwMjAtMDQtMTUiLCAiMjAyMC0wNC0yMCIsICIyMDIwLTA0LTI1IiwgIjIwMjAtMDQtMzAiLA0KICAgICAgICAgICAgICAiMjAyMC0wOC0wNSIsICIyMDIwLTA4LTEwIiwgIjIwMjAtMDgtMTUiLCAiMjAyMC0wOC0yMCIsICIyMDIwLTA4LTI1IiwgIjIwMjAtMDgtMzAiLA0KICAgICAgICAgICAgICAiMjAyMC0wOS0wNSIsICIyMDIwLTA5LTEwIiwgIjIwMjAtMDktMTUiLCAiMjAyMC0wOS0yMCIsICIyMDIwLTA5LTI1IiwgIjIwMjAtMDktMzAiLA0KICAgICAgICAgICAgICAiMjAyMC0xMC0wNSIsICIyMDIwLTEwLTEwIiwgIjIwMjAtMTAtMTUiLCAiMjAyMC0xMC0yMCIsICIyMDIwLTEwLTI1IiwgIjIwMjAtMTAtMzAiDQogICAgICAgICAgICAgICkNCg0KaHZ0REFQIDwtIDE4MA0KDQpDUCA8LSBDcm9wUGFyYW1zTGlzdFtjKCJBTUEiLCAiQlJFIiwgIkhVRSIsICJQT0QiLCAiWVVOIildDQpDUGFyYW1zIDwtIGxpc3QoQ1BbWzFdXSwgQ1BbWzJdXSwgQ1BbWzNdXSwgQ1BbWzRdXSwgQ1BbWzVdXSkgIA0KZW1nRGF5cyA8LSBFRGF5DQoNCndkYXRhIDwtIGFzLmRhdGEuZnJhbWUoV0QpDQp3ZGF0YSRzdW5zaCA8LSBwaG90b3BlcmlvZCh3ZGF0YSRkYXRlLCAtNy43NSkNCndkYXRhJHRtYXggPSB3ZGF0YSR0bWF4ICsgMS4wDQp3ZGF0YSR0bWluID0gd2RhdGEkdG1pbiArIDEuMA0KDQpvMCA8LSBhcy5kYXRhLmZyYW1lKG1hdHJpeChucm93ID0gbGVuZ3RoKG55ZWFycyksIG5jb2wgPSBsZW5ndGgoc3dnRGF0ZXMpKSkNCm8xIDwtIGFzLmRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSBsZW5ndGgobnllYXJzKSwgbmNvbCA9IGxlbmd0aChzd2dEYXRlcykpKQ0KbzIgPC0gYXMuZGF0YS5mcmFtZShtYXRyaXgobnJvdyA9IGxlbmd0aChueWVhcnMpLCBuY29sID0gbGVuZ3RoKHN3Z0RhdGVzKSkpDQpvMyA8LSBhcy5kYXRhLmZyYW1lKG1hdHJpeChucm93ID0gbGVuZ3RoKG55ZWFycyksIG5jb2wgPSBsZW5ndGgoc3dnRGF0ZXMpKSkNCm80IDwtIGFzLmRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSBsZW5ndGgobnllYXJzKSwgbmNvbCA9IGxlbmd0aChzd2dEYXRlcykpKQ0KbzUgPC0gYXMuZGF0YS5mcmFtZShtYXRyaXgobnJvdyA9IGxlbmd0aChueWVhcnMpLCBuY29sID0gbGVuZ3RoKHN3Z0RhdGVzKSkpDQoNCiNjbmFtZSA8LSAgIGMoIkFNQSIsICJCUkUiLCAiSFVFIiwgIlBPRCIsICJZVU4iKQ0KDQpjb2xuYW1lcyhvMCkgPC0gY29sbmFtZXMobzEpIDwtIGNvbG5hbWVzKG8yKSA8LSBjb2xuYW1lcyhvMykgPC0gY29sbmFtZXMobzQpIDwtIGNvbG5hbWVzKG81KSA8LSBzd2dEYXRlcw0Kcm93bmFtZXMobzApIDwtIHJvd25hbWVzKG8xKSA8LSByb3duYW1lcyhvMikgPC0gcm93bmFtZXMobzMpIDwtIHJvd25hbWVzKG80KSA8LSByb3duYW1lcyhvNSkgPC0gbnllYXJzDQoNCmZvcihpIGluIDE6bGVuZ3RoKG55ZWFycykpew0KICANCiAgZm9yKGogaW4gMTpsZW5ndGgoc3dnRGF0ZXMpKXsNCiAgICANCiAgICBzd2cgPC0gc3dnRGF0ZXNbal0NCiAgICB3ZWF0aGVyIDwtIHdkYXRhDQogICAgc293aW5nIDwtIHBhc3RlKG55ZWFyc1tpXSwgbW9udGgoc3dnKSwgZGF5KHN3ZyksIHNlcCA9ICItIikNCiAgICBzb3dpbmcgPC0gYXMuRGF0ZShzb3dpbmcpDQogICAgI2hhcnZlc3QgPC0gcGFzdGUobnllYXJzW2ldKzEsIG1vbnRoKGh2dCksIGRheShodnQpLCBzZXAgPSAiLSIpDQogICAgaGFydmVzdCA8LSBhcy5EYXRlKHNvd2luZykgKyBodnREQVANCiAgICBwbGFudERlbnNpdHkgPSAzLjMzDQogICAgI2s9Mi41DQogICAgDQogICAgI0FNQQ0KICAgIEVtZXJnZW5jeURheXMgPC0gZW1nRGF5c1sxXQ0KICAgIENyb3BQYXJhbXMgPC0gQ1BhcmFtc1tbMV1dDQogICAgcmVzIDwtIFNvbGFudW1Nb2RlbCh3ZWF0aGVyLCBzb3dpbmcsIGhhcnZlc3QsIEVtZXJnZW5jeURheXMsIHBsYW50RGVuc2l0eSwgQ3JvcFBhcmFtcykNCiAgICBubiA8LSBucm93KHJlcykNCiAgICBvMFtpLCBqXSA8LSBhcy5jaGFyYWN0ZXIocmVzJGRhdGVbMV0pDQogICAgbzFbaSwgal0gPC0gcm91bmQocmVzJGZ0eVtubl0sIDEpKnJ1bmlmKDEsMC44NSwxLjE1KSozLjkNCiAgICANCiAgICAjQlJFDQogICAgRURheSA8LSBlbWdEYXlzWzJdDQogICAgQ3JvcFBhcmFtcyA8LSBDUGFyYW1zW1syXV0NCiAgICByZXMgPC0gU29sYW51bU1vZGVsKHdlYXRoZXIsIHNvd2luZywgaGFydmVzdCwgRURheSxwbGFudERlbnNpdHksIENyb3BQYXJhbXMpDQogICAgbm4gPC0gbnJvdyhyZXMpDQogICAgbzJbaSwgal0gPC0gcm91bmQocmVzJGZ0eVtubl0sIDEpKnJ1bmlmKDEsMC44NSwxLjE1KSo1LjMNCiAgICANCiAgICAjSFVFDQogICAgRURheSA8LSBlbWdEYXlzWzNdDQogICAgQ3JvcFBhcmFtcyA8LSBDUGFyYW1zW1szXV0NCiAgICByZXMgPC0gU29sYW51bU1vZGVsKHdlYXRoZXIsIHNvd2luZywgaGFydmVzdCwgRURheSxwbGFudERlbnNpdHksIENyb3BQYXJhbXMpDQogICAgbm4gPC0gbnJvdyhyZXMpDQogICAgbzNbaSwgal0gPC0gcm91bmQocmVzJGZ0eVtubl0sIDEpKnJ1bmlmKDEsMC44NSwxLjE1KSo0LjUNCiAgICANCiAgICAjUE9EDQogICAgRURheSA8LSBlbWdEYXlzWzRdDQogICAgQ3JvcFBhcmFtcyA8LSBDUGFyYW1zW1s0XV0NCiAgICByZXMgPC0gU29sYW51bU1vZGVsKHdlYXRoZXIsIHNvd2luZywgaGFydmVzdCwgRURheSxwbGFudERlbnNpdHksIENyb3BQYXJhbXMpDQogICAgbm4gPC0gbnJvdyhyZXMpDQogICAgbzRbaSwgal0gPC0gcm91bmQocmVzJGZ0eVtubl0sIDEpKnJ1bmlmKDEsMC44NSwxLjE1KSo0LjMNCiAgICANCiAgICAjWVVODQogICAgRURheSA8LSBlbWdEYXlzWzVdDQogICAgQ3JvcFBhcmFtcyA8LSBDUGFyYW1zW1s1XV0NCiAgICByZXMgPC0gU29sYW51bU1vZGVsKHdlYXRoZXIsIHNvd2luZywgaGFydmVzdCwgRURheSxwbGFudERlbnNpdHksIENyb3BQYXJhbXMpDQogICAgbm4gPC0gbnJvdyhyZXMpDQogICAgbzVbaSwgal0gPC0gcm91bmQocmVzJGZ0eVtubl0sIDEpKnJ1bmlmKDEsMC44NSwxLjE1KSozLjINCiAgfQ0KfQ0KDQoNCkZUWW1lYW4gPC0gYXBwbHkob3V0RlRZWywyOjZdLDIsbWF4LG5hLnJtPVRSVUUpDQojYXBwbHkobzEsMixtZWFuKQ0KDQpvdXRZUCA8LSBsaXN0KEFNQSA9IG8xLCBCUkUgPSBvMiwgSFVFID0gbzMsIFBPRCA9IG80LCBZVU4gPSBvNSkNCg0Kb1BEIDwtIGMoIjIwMjAtMDgtMTUiLCIyMDIwLTA4LTIwIiwiMjAyMC0wOC0yNSIpDQojb1BEIDwtIGMoIjIwMjAtMDktMjUiKQ0KDQphUEQgPC0gYygiMjAyMC0wMy0yMCIsIjIwMjAtMDMtMjUiLCIyMDIwLTAzLTMwIiwiMjAyMC0wNC0wNSIsIjIwMjAtMDQtMTAiLA0KICAgICAgICAgIjIwMjAtMDktMDUiLCIyMDIwLTA5LTEwIiwiMjAyMC0wOS0xNSIsIjIwMjAtMDktMjAiLCIyMDIwLTA5LTI1IikNCg0KI2FQRCA8LSBjKCIyMDIwLTA5LTA1IiwiMjAyMC0wOS0xMCIsIjIwMjAtMDktMTUiLCIyMDIwLTA5LTIwIiwiMjAyMC0wOS0yNSIpDQoNCiMjIyBZUGE6IE9wdGltdW0gcGxhbnRpbmcgZGF0ZSAmIGhpZ2hlc3QgaGllbGRpbmcgdmFyaWV0eQ0KeXBhIDwtIG91dFlQJEFNQVssb1BEXQ0KeXBhIDwtIHVubGlzdCh5cGEpDQpZUGFfbWVhbiA8LSBtZWFuKHlwYSkNCllQYV9zZSA8LSBzZCh5cGEpL3NxcnQobGVuZ3RoKHlwYSkpDQoNCiMjIyBZUGI6IGFjdHVhbCBwbGFudGluZyBkYXRlICYgaGlnaGVzdCBoaWVsZGluZyB2YXJpZXR5DQp5cGIgPC0gb3V0WVAkQU1BWyxhUERdDQp5cGIgPC0gdW5saXN0KHlwYikNCllQYl9tZWFuIDwtIG1lYW4oeXBiKQ0KWVBiX3NlIDwtIHNkKHlwYikvc3FydChsZW5ndGgoeXBiKSkNCg0KIyMjIFlQYzogYWN0dWFsIHBsYW50aW5nIGRhdGUgJiBhY3R1YWwgdmFyaWV0eQ0KYTEgPC0gb3V0WVAkQU1BWyxhUERdDQphMiA8LSBvdXRZUCRCUkVbLGFQRF0NCmEzIDwtIG91dFlQJEhVRVssYVBEXQ0KYTQgPC0gb3V0WVAkUE9EWyxhUERdDQphNSA8LSBvdXRZUCRZVU5bLGFQRF0NCg0KeXBjIDwtIGModW5saXN0KGExKSx1bmxpc3QoYTIpLHVubGlzdChhMyksdW5saXN0KGE0KSx1bmxpc3QoYTUpKQ0KWVBjX21lYW4gPC0gbWVhbih5cGMpDQpZUGNfc2UgPC0gc2QoeXBjKS9zcXJ0KGxlbmd0aCh5cGMpKQ0KDQptZWFucz1jKFlQYV9tZWFuLFlQYl9tZWFuLFlQY19tZWFuKQ0Kc3RkZXJyPWMoWVBhX3NlLFlQYl9zZSxZUGNfc2UpDQoNCiMgUGxvdCBQb3RlbnRpYWwgeWllbGRzDQpicD1iYXJwbG90KG1lYW5zLCBsYXM9MSwgeWxpbT1jKDAsODApLCBjb2w9YygiYmx1ZSIsInJlZCIsImdyZWVuIiksDQogICAgICAgICAgIG5hbWVzLmFyZz1jKCJZUGEiLCAiWVBiIiwgIllQYyIpLCB5bGFiPSJQb3RlbnRpYWwgeWllbGQgbGV2ZWxzICh0L2hhKSIpDQoNCmFycm93cyh4MCA9IGJwLCB5MCA9IG1lYW5zIC0gc3RkZXJyLCB4MSA9IGJwLCB5MSA9IG1lYW5zICsgc3RkZXJyLCANCiAgICAgICBhbmdsZSA9IDkwLCBjb2RlID0gMywgbGVuZ3RoID0gMC4xLCBjb2wgPSAiYmxhY2siKQ0KDQoNCmBgYA0KDQoNCg0KIyMgU3VydmV5IGRhdGEgY29sbGVjdGlvbg0KDQpgYGB7cn0NCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIDMuIFRoZXJtYWwgdGltZSBjb21wdXRpbmcNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiN5ZWFyMCA9IDIwMDANCiN5ZWFyMSA9IDIwMjINCiNuIDwtIGFzLkRhdGUoIjIwMjMtMDEtMzEiKS1hcy5EYXRlKCIyMDIyLTExLTAxIikrMQ0KI20gPC0geWVhcjEteWVhcjArMQ0KIw0KIyN3ZGF0YSA8LSB3ZGF0YVt3ZGF0YSRZRUFSPj15ZWFyMCAmICN3ZGF0YSRZRUFSPD15ZWFyMSxdDQojDQojb3V0MCA8LSBhcy5kYXRhLmZyYW1lKG1hdHJpeChucm93ID0gbiwgbmNvbCA9IG0pKQ0KI291dDEgPC0gYXMuZGF0YS5mcmFtZShtYXRyaXgobnJvdyA9IG4sIG5jb2wgPSBtKSkNCiNvdXQyIDwtIGFzLmRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSBuLCBuY29sID0gbSkpDQojeXkgPSBzZXEoeWVhcjAsIHllYXIxLCBieSA9IDEpDQojDQojIyBsb2FkIGV4dHJhIGZ1bmN0aW9ucw0KIw0KIw0KIw0KIw0KI3dlYXRoZXIgPC0gd2RhdGENCiMNCiMjZm9yKGpqIGluIDE6bSl7DQojIyAgDQojIyAgZGF0ZTAgPSBhcy5EYXRlKHBhc3RlMCh5eVtqal0sICItMTEtMDEiKSktMQ0KIyMgIA0KIyMgIGZvcihpaSBpbiAxOm4pew0KIyMgIA0KIyMgICAgDQojIyAgICBzRGF0ZSA9IGFzLkRhdGUoZGF0ZTAgKyBpaSkNCiMjICAgIHNEYXRlLm5hbWUgPSBwYXN0ZShtb250aChzRGF0ZSksIGRheShzRGF0ZSksIHNlcCAjPSAiLSIpDQojIyAgICBvdXQwW2lpLCBqal0gPSBhcy5jaGFyYWN0ZXIoc0RhdGUpDQojIyAgICANCiMjICAgIHNvd2luZyA9IHNEYXRlDQojIyAgICBoYXJ2ZXN0ID0gc293aW5nICsgOTANCiMjICAgIG5kYXlzID0gYXMubnVtZXJpYyhoYXJ2ZXN0LXNvd2luZykrMQ0KIyMgICAgDQojIyMjIHZhcmlldHkgQmFyaSBBbHUgNzIgICAgDQojIyAgICBzb3VyY2UoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9qbmluYW55I2EvUmFtaXJlei1ldC1hI2wtMjAyNC9tYWluL3NvbGFudW1SL0JBUkktQWx1LTcyLlIiKQ0KIyMgICAgc291cmNlKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vam5pbmFueSNhL1JhbWlyZXotZXQtYSNsLTIwMjQvbWFpbi9zb2xhbnVtUi9Nb2R1bGVfUG90ZW50aWFsR3Ijb3d0aF9WMi4wLlIiKQ0KIyMgICAgDQojIyAgICBvdXQxW2lpLCBqal0gPSBpZmVsc2UoZGYkZnR5W25kYXlzXT4yMCwgI2RmJGZ0eVtuZGF5c10sIE5BKQ0KIyMgICAgDQojIyMjIHZhcmlldHkgQmFyaSBBbHUgNzgNCiMjICAgIHNvdXJjZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2puaW5hbnkjYS9SYW1pcmV6LWV0LWEjbC0yMDI0L21haW4vc29sYW51bVIvQkFSSS1BbHUtNzguUiIpDQojIyAgICBzb3VyY2UoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9qbmluYW55I2EvUmFtaXJlei1ldC1hI2wtMjAyNC9tYWluL3NvbGFudW1SL01vZHVsZV9Qb3RlbnRpYWxHciNvd3RoX1YyLjAuUiIpDQojIyAgICANCiMjICAgIG91dDJbaWksIGpqXSA9IGlmZWxzZShkZiRmdHlbbmRheXNdPjIwLCAjZGYkZnR5W25kYXlzXSwgTkEpDQojIyAgICANCiMjICAgIHJvd25hbWVzKG91dDApW2lpXSA9IHNEYXRlLm5hbWUNCiMjICAgIHJvd25hbWVzKG91dDEpW2lpXSA9IHNEYXRlLm5hbWUNCiMjICAgIHJvd25hbWVzKG91dDIpW2lpXSA9IHNEYXRlLm5hbWUNCiMjICB9DQojIyAgDQojIyAgY29sbmFtZXMob3V0MClbampdID0geXlbampdDQojIyAgY29sbmFtZXMob3V0MSlbampdID0geXlbampdDQojIyAgY29sbmFtZXMob3V0MilbampdID0geXlbampdDQojIyAgDQojI30NCiMNCiMjZDEgPC0gb3V0MQ0KIyNkMiA8LSBvdXQyDQojIw0KIyNib3hwbG90KHQoZDEpLCBjb2wgPSAiZ3JlZW4iLCBvdXRsaW5lID0gRkFMU0UsIGxhcz0xLA0KIyMgICAgICAgIHlsYWIgPSAicG90ZW50aWFsIHlpZWxkICh0L2hhKSIpDQojIw0KIyNib3hwbG90KHQoZDIpLCBjb2wgPSAicmVkIiwgb3V0bGluZSA9IEZBTFNFLCBsYXM9MSwNCiMjICAgICAgICB5bGFiID0gInBvdGVudGlhbCB5aWVsZCAodC9oYSkiKQ0KIyMNCiMjDQojIyMjIHBsb3QgZnR5IGJ5IHBsYW50aW5nIGRhdGUNCiMjeCA8LSAxOjkyDQojI2Z0eV9tZWFuIDwtIGFwcGx5KG91dDEsIDEsIG1lYW4sIG5hLnJtID0gVFJVRSkNCiMjZnR5X3ExMCA8LSBhcHBseShvdXQxLCAxLCBxdWFudGlsZSwgcHJvYnMgPSAwLjEwLCAjbmEucm0gPSBUUlVFKQ0KIyNmdHlfcTkwIDwtIGFwcGx5KG91dDEsIDEsIHF1YW50aWxlLCBwcm9icyA9IDAuOTAsICNuYS5ybSA9IFRSVUUpDQojIw0KIyMNCiMjIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIyMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyMjIyMgR2VuZXJhbCBmaWd1cmUgc2V0dGluZ3MNCiMjcGFyKG9tYSA9IGMoNCwgMSwgMC41LCAwLjUpLCAgIyBnZW5lcmFsIG1hcmdpbnMNCiMjICAgIG1mcm93ID0gYygyLCAxKSwgICAgICAgICAgICAgICMgbnVtYmVyIG9mICNzdWItZmlndXJlcw0KIyMgICAgbWFyID0gYygwLDMsMCwwKSwgICAgICAgICAgICMgbWFyZ2lucyBwZXIgI3N1Yi1maWd1cmUNCiMjIyAgICBwcyA9IDEwLCAgICAgICAgICAgICAgICAgICAgICAjIHRleHQgZm9udCBzaXplDQojIyAgICBmYW1pbHkgPSAic2VyaWYiICAgICAgICAgICAgICAjIHRleHQgZmFtaWx5DQojIyMgICAgbHdkID0gMC41LCAgICAgICAgICAgICAgICAgICAgIyBsaW5lIHdpZHRoDQojIyMgICAgbGFzID0gMSwgICAgICAgICAgICAgICAgICAgICAgIyBzdHlsZSBvZiBheGlzICNsYWJlbHMNCiMjIyAgICBwY2ggPSAyMCAgICAgICAgICAgICAgICAgICAgICAjIHBsb3R0aW5nIHBvaW50cw0KIyMpDQojIw0KIyN4PTE6OTANCiMjeTE9ZDEkYDIwMjFgWzE6OTBdDQojI3kyPWQyJGAyMDIxYFsxOjkwXQ0KIyNwbG90KHgsIHkxLCB0eXBlID0gImwiLCB4bGltID0gYygxLDkyKSwgeWxpbSA9ICNjKDIzLDU3KSwgDQojIyAgICAgeGxhYiA9ICIiLCB5bGFiID0gInBvdGVudGlhbCB5aWVsZCAodC9oYSkiLCBheGVzICM9IEZBTFNFLCANCiMjICAgICBsd2QgPSAyKQ0KIyNib3goKQ0KIyNsaW5lcyh4LCB5MiwgbHdkID0gMiwgY29sID0gImdyYXk1MCIpDQojIw0KIyMjYXhpcygxLCBhdCA9IGMoNSwxNSwyNSwzNSw0NSw1NSw2Niw3Niw4NiksIGxhcyA9IDIsDQojIyMgICAgIGxhYmVscyA9ICNjKCI1LW5vdiIsIjE1LW5vdiIsIjI1LW5vdiIsIjUtZGVjIiwiMTUtZGVjIiwiMjUtZGVjIyIjLCI1LWphbiIsIjE1LWphbiIsIjI1LWphbiIpKQ0KIyMjYXhpcygxLCBsYXMgPSAxLCBhdCA9IHNlcSg1LCA5MCwgYnk9MTApKQ0KIyNheGlzKDIsIGxhcyA9IDEsIGF0PXNlcSgyNSw1NSxieT01KSkNCiMjYWJsaW5lKHY9NTAsIGx0eSA9IDIsIGNvbCA9ICJibHVlIikNCiMjYWJsaW5lKHY9NzQsIGx0eSA9IDIsIGNvbCA9ICJibHVlIikNCiMjDQojI3RleHQoNDcsIDU1LjUsICJaVCIsIGNvbCA9ICJibHVlIikNCiMjdGV4dCg3MSwgNTUuNSwgIkNUIiwgY29sID0gImJsdWUiKQ0KIyMNCiMjdGV4dCgwLCA1NS41LCBleHByZXNzaW9uKGJvbGQoIkEiKSkpDQojI210ZXh0KHNpZGU9MiwgdGV4dD1icXVvdGUoInlpZWxkICh0IGhhIl57Ii0xIn0qIikiKSwgI2NleCA9IDEuNSwgI2xpbmUgPSAyLjQpDQojIw0KIyMjIyMNCiMjeD0xOjg1DQojI3kxPWQxJGAyMDIyYFsxOjg1XQ0KIyN5Mj1kMiRgMjAyMmBbMTo4NV0NCiMjcGxvdCh4LCB5MSwgdHlwZSA9ICJsIiwgeGxpbSA9IGMoMSw5MiksIHlsaW0gPSAjYygyMyw1MiksIA0KIyMgICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJwb3RlbnRpYWwgeWllbGQgKHQvaGEpIiwgYXhlcyAjPSBGQUxTRSwgDQojIyAgICAgbHdkID0gMikNCiMjYm94KCkNCiMjbGluZXMoeCwgeTIsIGx3ZCA9IDIsIGNvbCA9ICJncmF5NTAiKQ0KIyMNCiMjYXhpcygxLCBhdCA9IGMoNSwxNSwyNSwzNSw0NSw1NSw2Niw3Niw4NiksIGxhcyA9IDIsDQojIyAgICAgbGFiZWxzID0gI2MoIjA1LW5vdiIsIjE1LW5vdiIsIjI1LW5vdiIsIjA1LWRlYyIsIjE1LWRlYyIsIjI1LWRlI2MiLCIwNS1qYW4iLCIxNS1qYW4iLCIyNS1qYW4iKSkNCiMjYXhpcygxLCBsYXMgPSAxLCBhdCA9IHNlcSg1LCA5MCwgYnk9MTApKQ0KI2F4aXMoMiwgbGFzID0gMSwgYXQ9c2VxKDI1LDUwLGJ5PTUpKQ0KI2FibGluZSh2PTQ0LCBsdHkgPSAyLCBjb2wgPSAiYmx1ZSIpDQojYWJsaW5lKHY9NjIsIGx0eSA9IDIsIGNvbCA9ICJibHVlIikNCiMNCiN0ZXh0KDQxLCA1MSwgIlpUIiwgY29sID0gImJsdWUiKQ0KI3RleHQoNTksIDUxLCAiQ1QiLCBjb2wgPSAiYmx1ZSIpDQojDQojdGV4dCgwLCA1MSwgZXhwcmVzc2lvbihib2xkKCJCIikpKQ0KIw0KI210ZXh0KHNpZGU9MiwgdGV4dD1icXVvdGUoInlpZWxkICh0IGhhIl57Ii0xIn0qIikiKSwgY2V4ID0gMS41LCAjbGluZSA9IDIuNCkNCiMNCg0KDQoNCg0KDQoNCg0KDQoNCmBgYA0KDQojIyBTdG9jaGFzdGljIEZyb250aWVyIEFuYWx5c2lzDQoNCg0KIyMgUmVmZXJlbmNlcw0KDQoxLiBbSGFyYWhhZ2F6d2UgZXQgYWwuICgyMDE4KV0oI0hhcmFoYWdhendlLWV0LWFsLTIwMTgpDQoNCg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCiMgS25pdCBpbmRleC5SbWQgdHdvIHRpbWVzDQpmaWxlLmNvcHkoZnJvbSA9ICIuL2luZGV4Lmh0bWwiLCB0byA9ICIuLi9kb2NzLyIsIG92ZXJ3cml0ZSA9IFRSVUUpICAgICAgICAgICAgDQpgYGANCg0KDQoNCg0KDQoNCg0KDQo=